今天想和大家分享一次我前不久在某次授权攻防演练中挖到的高危逻辑漏洞。这个漏洞没有用到任何复杂的 0day,仅仅是通过对系统业务逻辑的死磕,就从一个不起眼的前端 JS 文件起步,最终实现了对目标高校统一身份认证平台(SSO)的任意用户接管,横向获取了近 几十万条敏感信息。
希望这篇复盘能给大家带来一些关于“业务逻辑安全”的启发!
0x01 故事背景
在渗透测试的初期,我拿到的目标是某高校的“网上办事大厅”。这是一个典型的单点登录(SSO)入口,防护相当严密:强密码策略、验证码、甚至还有设备指纹校验。常规的爆破和注入在这里统统碰了壁。
本以为这次的边界突破会异常艰难,但谁能想到,整个校园网的安全防线,最后竟因为一段为了“方便开发”而裸奔的 API 接口轰然倒塌?
只要知道一个人的学号,就能不需要密码直接登入他的账号,甚至还能悄无声息地重置他的密码。这听起来是不是像天方夜谭?但它确实发生了。
0x02 信息收集
在常规 Web 端一无所获后,我决定转变思路,开始对目标系统的前端资产进行深度挖掘。
我打开了浏览器的开发者工具,开始在这个办事大厅的登录页翻阅加载的 JS 文件。很快,一个体积不小的打包文件 index-xxxxxx.js 引起了我的注意。在这个混淆过的 JS 海洋里,我习惯性地搜索诸如 api/、login、token 等关键词。
突然,一行极其突兀的接口路径跳进了我的视线:
sso.example-edu.com/api/finddata/wechat_account

“微信账号查找?” 作为一个经常和各种接入了微信生态的高校系统打交道的测试员,我的安全直觉雷达瞬间狂响。很多系统在处理微信扫码登录或公众号静默授权时,常常会因为 OAuth 流程校验不严导致鉴权绕过。
这个接口是干什么用的?它需要鉴权吗?带着这些疑问,我立刻将接口扔进工具中构造请求。
0x03 漏洞利用
这里是整个渗透过程中最让人血脉喷张的“逻辑转换”瞬间。
我尝试向这个接口发送了一个极其简单的 JSON 请求,尝试查询一个已知的测试学号(比如 2023xxxx):
POST /api/finddata/wechat_account HTTP/1.1
Host: sso.example-edu.com
Content-Type: application/json
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36...
{"findobj":"{\"account\":\"2023xxxx\"}"}
服务器没有返回 401 Unauthorized,也没有返回 403 Forbidden,而是直接吐出了一长串极其敏感的用户信息,其中最致命的,是包含了一个 openid 字段!

{
"state": true,
"value": [
{
"account": "2023xxxx",
"openid": "oI_dummy_OPENID_xxxxxx_For_Test",
"created_at": "...",
...
}
]
}
思路转换:从信息泄露到权限接管
拿到 openid 意味着什么?在微信生态中,openid 相当于用户在这个应用下的“身份证号”。
我立刻联想到目标学校有一个微信公众号版本的网上办事大厅。我用自己的测试账号在微信客户端里抓包,分析正常的公众号登录流程。我发现,当用户通过微信访问系统时:
- 系统前端会向后端发送请求获取当前微信的 openid。
- 后端如果发现这个 openid 已经绑定了某个学号,就会直接放行,自动登录!
这中间存在一个致命的逻辑断层:系统完全信任了前端传回或拦截器中替换的 openid,而没有去校验这个 openid 是否真的来源于微信服务器的官方 OAuth 回调授权!
于是,攻击链彻底闭环:
1.无需登录,通过越权 API 用【目标学号】查出对应的【目标 OpenID】。

2.在微信端访问公众号大厅,拦截授权请求包,当出现请求:
https://wchattest.xxx.edu.cn/wx/api/auth/getopenid时,替换返回的openid为获取到的目标用户的openid

3.放行数据包——Boom!系统直接将我识别为了目标用户,成功登录!
更绝的是,登录成功后,在“我的-设置”页面,系统提供了一个修改密码的功能。而这个功能居然不需要校验原密码!我直接将目标用户的密码重置为了强密码,随后回到 Web 端使用学号和新密码成功登入目标系统最高权限的管理员账号。


然后可以使用修改后的密码前往统一身份认证平台进行登录

成功接管管理员账号,实现了统一身份认证平台任意用户密码重置
0x04 漏洞影响
由于目标账号属于信息中心的教务系统管理员,登入后看到的景象让人倒吸一口凉气。
整个后台对我完全敞开。通过对系统权限的遍历,我能够直接读取全校所有学生的个人详细信息(约 69,000 余条),以及所有教职工和外聘人员的信息(约 3,700 余条),这些数据中甚至包含了身份证号等极度敏感的个人隐私。
如果这不是一次授权的演练,而是一次真实的黑产攻击,这数万名师生的信息一旦流入暗网,后果不堪设想。而这一切的起点,仅仅只是一个没有加鉴权的 API 接口。
0x05 防御与反思
在完成报告并提交给防守方后,作为攻击者,我也不禁反思:为什么这种教科书级别的逻辑漏洞在今天依然屡见不鲜?
Root Cause (根因分析):
- 未授权访问 (Insecure Direct Object Reference / IDOR):/api/finddata/wechat_account 接口缺乏最基础的身份认证(Authentication)和权限校验(Authorization)。开发者可能认为这个接口“隐藏在源码里”,没有人会发现,典型的“隐蔽式安全 (Security by Obscurity)”谬误。
- 信任域配置错误 (Broken Authentication):在处理微信 SSO 时,业务系统过度信任了客户端传来的参数。真正的安全设计应当是通过微信的 OAuth2.0 流程,后端拿着前端提供的 code 去微信服务器换取 access_token 和 openid,而不是直接接收前端明文传输的 openid 并以此作为鉴权凭据。
给开发者的加固建议:
- 收敛 API 暴露面:立即对 wechat_account 等内部数据查询接口增加严格的 Token 校验,确保只有高权限的后端服务可以调用,阻断未授权的信息泄露。
- 重构 SSO 鉴权逻辑:废弃直接通过参数传递 openid 进行静默登录的做法,必须严格执行 OAuth2.0 规范,所有第三方身份校验操作必须在服务器后端与第三方服务(微信)之间闭环完成。
- 敏感操作二次校验:在密码重置、密保修改等高危场景下,即使是在已登录状态,也必须强制要求输入旧密码或通过手机短信/动态令牌进行二次身份确认。
这次挖掘经历再次印证了一句话:系统的安全性往往取决于它最薄弱的那一环。 作为安全研究员,我们就是要用黑客的视角去打破开发者的常规思维,在风暴来临前,替系统补上最后一块短板。