前端无秘密:看我如何策反JS为我所用(下)
字数 1497 2025-08-15 21:32:51
前端安全分析:绕过参数签名与防重放机制实战教学
1. 背景与发现
在金融行业某私测项目中,发现一个业务办理页面存在以下特征:
- 需要向客户发送短信验证码
- 响应报文中包含大段加密数据
- 全站并非全参数加密,加密参数可疑
- 篡改密文会导致"实名认证异常"提示
初步判断该密文涉及用户信息,且通过前端JS进行解密。
2. 漏洞分析
2.1 加密数据解密
通过分析前端JS代码,发现:
- 加密数据在前端进行解密
- 解密后的数据包含用户敏感信息(姓名、单位地址、家庭地址、身份证号码等)
2.2 参数签名机制
系统采用以下安全机制:
- 防篡改:客户端对所有请求参数进行哈希计算,生成签名(sign)
- 防重放:签名一次性使用,重复签名会被拒绝
签名流程:
- 客户端生成签名放入authorization头部
- 服务端基于相同信息生成签名
- 比较客户端和服务端签名
- 不同 → 参数被篡改 → 拒绝请求
- 相同 → 检查是否重复使用
- 重复 → 请求被重放 → 拒绝请求
- 不重复 → 处理请求
3. 绕过防御机制
3.1 识别签名关键点
通过Burp Suite测试发现:
- 修改PHONE_NO参数会导致"参数签名异常"错误
- 重放相同请求会导致"条件不达标"(412 Precondition Failed)错误
- authorization头部结构:
origin=2|appkey=200000056|token=null|ts=1605169433400|noncestr=K2FZpfbe|sign=40ca525898eba6df88bca451342515c1
3.2 定位签名生成逻辑
通过前端代码分析:
- 全局搜索sign关键字,定位到1875行的
_e()函数 - 该函数负责:
- 计算签名(s)
- 生成authorization值
3.3 动态调试签名生成
调试步骤:
- 在
_e()函数入口和出口设置断点 - 观察调用参数和返回值
- 通过控制台测试不同参数:
_e("POST", "{\"BODY\":{\"PHONE_NO\":\"13988888849\",\"GROUP_ID\":\"2\",\"REGION_ID\":\"11\"}}")
3.4 绕过签名验证
方法:
- 使用正确参数调用
_e()函数生成新签名 - 在请求中同时修改参数和对应的签名
- 确保每次请求使用新生成的签名
4. 武器化实现
4.1 方案选择
两种武器化方案:
- 复用报文方式:
- 高效
- 需要绕过防篡改和防重放
- 模拟操作方式:
- 使用webdriver模拟人工操作
- 实现简单但效率较低
4.2 关键脚本实现
4.2.1 签名生成脚本(gen_authorization.py)
将JS的_e()函数转换为Python实现,用于:
- 动态生成有效签名
- 绕过防篡改和防重放
4.2.2 数据解密脚本(decrypt_data_by_nodejs.py)
调用Node.js解密服务端返回的加密数据,获取:
- 用户姓名
- 单位地址
- 家庭地址
- 身份证号码
4.2.3 批量利用脚本(get_users_info_by_requests.py)
整合功能:
- 加载手机号码字典
- 为每个号码生成有效签名
- 调用接口获取加密数据
- 解密数据获取用户信息
5. 防御建议
5.1 服务端改进
-
增强签名机制:
- 使用更复杂的签名算法
- 加入服务端独有的密钥
-
完善防重放:
- 使用时间戳+随机数组合
- 缩短签名有效期
-
敏感数据保护:
- 避免在前端解密敏感数据
- 必要数据应进行脱敏处理
5.2 前端防护
-
代码混淆:
- 使用高级混淆工具
- 定期更新混淆方案
-
反调试措施:
- 检测调试器存在
- 触发调试时采取防御行为
-
关键逻辑保护:
- 将关键逻辑移至Web Worker
- 使用WebAssembly实现敏感操作
6. 总结
本案例展示了如何通过:
- 前端代码分析定位关键逻辑
- 动态调试理解签名生成机制
- 重放请求测试系统防御
- 将手工测试转化为自动化工具
最终实现了绕过参数签名和防重放机制,批量获取用户敏感信息的能力。这提醒我们前端安全同样重要,不能仅依赖参数签名等单一防御机制。