客户端可信数据的认证绕过
这一类漏洞的核心思想是:服务端用攻击者可控的请求成分(请求头、Cookie、请求体字段)做鉴权决策。鉴权数据一旦来自客户端,绕过就只是改一个值的事。
仅限授权环境
认证绕过测试只允许在授权靶场或明确授权的范围内进行,并避免影响真实用户会话。
手法清单
| 可控成分 | 手法 | 触发条件 |
|---|---|---|
X-Forwarded-For 头 | 伪造 127.0.0.1 绕过 IP 白名单 | 服务端只信任该头,不校验真实链路 |
Referer 头 | 含 Host 字符串即跳过 JWT 校验 | 校验逻辑误用 Referer 做“本站”判断 |
| 自定义 debug 头 | X-Sentinel-Debug: 1 直接发 token | 调试开关遗留在线上且无鉴权 |
| Cookie | 篡改服务端信任的分数/状态值 | 状态存客户端且无签名校验 |
| 请求体字段 | tenant_id: "system" 跨租户 | 租户上下文取自请求体而非会话 |
方法 A:伪造请求头
X-Forwarded-For 绕过 IP 白名单
curl -sS -H 'X-Forwarded-For: 127.0.0.1' http://target/admin
仅当服务端 只看这个头 判定“来自本机”时生效;它伪造不了 TCP 层的真实来源。
Referer 顶替 JWT 校验
某些设计中,Referer 头里含 Host 字符串就视为“内部跳转”,跳过 JWT 校验。测试时只需带上:
curl -sS -H 'Referer: http://target/' http://target/api/protected
调试开关头
遗留的 debug 头可能直接放行认证并发 token:
curl -sS -H 'X-Sentinel-Debug: 1' http://target/auth
方法 B:篡改客户端状态
服务端若信任 Cookie 或请求体里提交的 分数、状态、租户 等值,直接改值即可越权:
# 跨租户:把请求体中的租户字段改成特权租户
{"tenant_id": "system", "action": "list"}
判断标准:这个值在服务端有没有与会话绑定的二次校验。没有,就是可篡改点。
方法 C:PHP strcmp() 数组混淆
strcmp() 比较数组与字符串时返回 NULL,而 NULL == 0 在松散比较下为真,导致比较逻辑被绕过:
# 提交数组参数,让 strcmp 返回 NULL
username[]=admin&password[]=foo
若代码写成 if (strcmp($user, $pass) == 0) 这类松散比较,登录校验直接通过。适用前提是目标为 PHP 且使用了 strcmp + 松散比较的组合。
方法 D:JWT 空密钥伪造
服务端用 空字符串密钥 验签 HS256 时,客户端可以用同样的空密钥签出任意 claims:
python3 -c 'import jwt; print(jwt.encode({"user": "admin", "role": "admin"}, "", algorithm="HS256"))'
常需配合 X-Forwarded-For: 127.0.0.1 通过依赖来源头的附加校验。拿到伪造 token 后替换 Cookie/Authorization 头重放请求确认。
定位信任点:差分测试
对每个可疑请求成分做 带/不带对照,观察状态码与响应体的差异:
| 对照组 | 请求 | 观察点 |
|---|---|---|
| 基线 | 不带该头/Cookie | 状态码、错误信息 |
| 实验 | 带伪造值 | 状态码是否变化、是否返回敏感数据 |
差分有反应的位置,就是服务端的信任点;再沿该点尝试最小化绕过。带畸形值(数组、空值、超长)的边界输入可进一步暴露松散比较与类型混淆问题。
复核要点
| 检查点 | 说明 |
|---|---|
| 鉴权依据来源 | 请求头、Cookie、请求体中的任何鉴权字段都要列为可疑 |
| 比较函数 | PHP 松散比较与 strcmp 数组返回值必须验证 |
| JWT 密钥 | 空密钥、弱密钥都要实测伪造 |
| 越权范围确认 | 用只读接口确认影响面,避免修改生产数据 |
防御建议
- 不用任何请求头(
X-Forwarded-For、Referer、自定义 debug 头)做鉴权决策。 - 会话状态、分数、租户上下文一律由服务端维护,客户端只传不透明 ID。
- 密码与 token 比较使用常量时间比较函数,并显式校验类型,避免
NULL == 0类混淆。 - JWT 使用足够强度的密钥并集中管理,禁止空密钥/默认密钥上线。
- 下线所有调试开关,或在网关层直接丢弃 debug 类请求头。