导语:挖漏洞这件事,有时候靠的不是工具扫描,而是一种”感觉哪里不对”的直觉。这次我要说的漏洞,不是SQL注入,不是命令执行,甚至没有任何报错信息——只是一个请求头里带着用户ID,结果整个账户的交易记录、奖励积分、账单偏好全部暴露。系统完全信任了这个来自客户端的参数,没做任何校验。
一、发现:一切看起来都”太干净了”
大多数漏洞系统都会”大声喊疼”——报错信息暴露了数据库结构,重定向跳到了不该去的地方,JSON格式乱得一塌糊涂。
但这一次,什么都没有。
目标平台看起来非常规范,接口整齐、响应统一、认证流程严谨——就是那种让人感觉”应该没什么问题”的系统。
正因如此,我才更想仔细看看。
我在抓包观察流量时,发现了一个请求头:
X-Account-Id: <user_id_here>
当时第一反应是:这是装饰性的请求头,可能是前端用来做路由分发的。
但仔细一想——路由分发用得着带用户ID吗?
这个头,太重要了。
二、验证:一个请求头的代价
我先用当前账号的SessionReplay了那个请求,Transaction History正常返回。
然后,我换了一个账号的ID,填进X-Account-Id里。
Session没变,Cookie没变,认证状态没变——唯一改动的就是这一个请求头的值。
发送。
返回了第二个账号的完整金融数据,包括交易记录、账户信息——就像我本来就有权限查看一样。
没有授权检查,没有所有者验证,没有任何阻力。
系统只是单纯地信任了这个来自客户端的值。

三、原理:后端把身份判断权交给了客户端
这个漏洞的本质,是典型的IDOR(Insecure Direct Object Reference,不安全的直接对象引用)。
正常情况下,当用户登录后,后端应该根据JWT里的用户身份去数据库里查询对应权限下的数据。但这套系统的做法是:前端在请求头里带一个X-Account-Id,后端直接拿这个值去查数据——至于这个值是不是当前登录用户的,没人管。
换句话说:
后端没有判断”这个数据属不属于你”,而是由客户端自己声明”我是谁”。
在金融系统里,这种设计等于把金库钥匙放在了用户口袋里,还告诉用户”请不要打开别人的金库”。
四、扩大战果:不止一个接口
确认了第一个接口/user/past_transactions存在漏洞后,我顺藤摸瓜检查了其他几个相关接口:
- Rewards(奖励积分):查到别人的积分余额和兑换记录
- Billing Preferences(账单偏好):查到别人的支付方式和账单设置
- Account-linked data(账户关联数据):各种关联信息
全部中招。
无一例外,全是服务端决策依赖客户端传来的ID这个问题。

五、测试边界:我没有越线
整个测试过程,我只用了自己的两个账号,没有去猜测或遍历别人的用户ID,没有访问其他用户的数据,没有做任何批量爬取。
理由很简单:漏洞本身已经足够明显,不需要碰别人的隐私也能说清楚问题。
这是负责任的安全研究员的基本素养。
六、报告与修复:24小时内拿奖金
报告提交后,厂商很快有了回应。
第一轮沟通是了解攻击面和影响范围,然后就是每个安全研究员都熟悉的环节——漏洞定级讨论。
我的观点很直接:金融场景下的交易数据泄露,在监管层面、隐私法规和威胁建模里都没有争议——它就是敏感数据。
后来随着更多接口被确认漏洞存在,厂商重新评估了严重程度,最终确认合理。
处理过程非常专业:响应快、问题清晰、善后到位。
从报告到奖金到账,用了不到24小时。
好团队不会推诿扯皮,他们会认真分析问题。他们做到了。
七、复盘:最简单的漏洞,最安静的错误
这个漏洞的出现,其实是一个非常普通的工作流程问题:
某个人为了方便路由,在请求里加了一个Header。
另外一个人写后端接口时,直接用了这个Header的值做数据查询,没有把它接入认证流程。
几个月过去了,没人发现。
系统安静地运转,安静地信任客户端永远不会说谎。
直到我多看了一眼那个”装饰性”的请求头。
安全这件事,从来不只是抓大的错误。有时候,是那些看起来平平无奇的东西,在做着它不该做的事。

八、经验总结
- 直觉很重要:看到”太干净”的系统,反而要多留个心眼。规范的表象下,往往藏着信任过度的设计
- 请求头不等于安全:所有来自客户端的数据都不可信,包括请求头、Cookie、参数——后端必须自己验证数据归属权
- IDOR在金融场景下是”上膛的枪”:不需要复杂利用,改一个ID就能拿到别人的数据,后果立竿见影
- 负责任的测试:用自己的账号验证,用最少的数据证明问题,不碰别人隐私
最后送上一句话:
复杂的东西不一定会打穿系统,有时候,恰恰是最简单的东西,捅了最大的窟窿。
版权声明:本文由华盟网原创发布,保留所有权利。配图由华盟网授权使用。














暂无评论内容