前端无秘密:看我如何策反JS为我所用(下)
字数 1497 2025-08-15 21:32:51

前端安全分析:绕过参数签名与防重放机制实战教学

1. 背景与发现

在金融行业某私测项目中,发现一个业务办理页面存在以下特征:

  • 需要向客户发送短信验证码
  • 响应报文中包含大段加密数据
  • 全站并非全参数加密,加密参数可疑
  • 篡改密文会导致"实名认证异常"提示

初步判断该密文涉及用户信息,且通过前端JS进行解密。

2. 漏洞分析

2.1 加密数据解密

通过分析前端JS代码,发现:

  1. 加密数据在前端进行解密
  2. 解密后的数据包含用户敏感信息(姓名、单位地址、家庭地址、身份证号码等)

2.2 参数签名机制

系统采用以下安全机制:

  1. 防篡改:客户端对所有请求参数进行哈希计算,生成签名(sign)
  2. 防重放:签名一次性使用,重复签名会被拒绝

签名流程:

  1. 客户端生成签名放入authorization头部
  2. 服务端基于相同信息生成签名
  3. 比较客户端和服务端签名
    • 不同 → 参数被篡改 → 拒绝请求
    • 相同 → 检查是否重复使用
      • 重复 → 请求被重放 → 拒绝请求
      • 不重复 → 处理请求

3. 绕过防御机制

3.1 识别签名关键点

通过Burp Suite测试发现:

  1. 修改PHONE_NO参数会导致"参数签名异常"错误
  2. 重放相同请求会导致"条件不达标"(412 Precondition Failed)错误
  3. authorization头部结构:
    origin=2|appkey=200000056|token=null|ts=1605169433400|noncestr=K2FZpfbe|sign=40ca525898eba6df88bca451342515c1
    

3.2 定位签名生成逻辑

通过前端代码分析:

  1. 全局搜索sign关键字,定位到1875行的_e()函数
  2. 该函数负责:
    • 计算签名(s)
    • 生成authorization值

3.3 动态调试签名生成

调试步骤:

  1. _e()函数入口和出口设置断点
  2. 观察调用参数和返回值
  3. 通过控制台测试不同参数:
    _e("POST", "{\"BODY\":{\"PHONE_NO\":\"13988888849\",\"GROUP_ID\":\"2\",\"REGION_ID\":\"11\"}}")
    

3.4 绕过签名验证

方法:

  1. 使用正确参数调用_e()函数生成新签名
  2. 在请求中同时修改参数和对应的签名
  3. 确保每次请求使用新生成的签名

4. 武器化实现

4.1 方案选择

两种武器化方案:

  1. 复用报文方式
    • 高效
    • 需要绕过防篡改和防重放
  2. 模拟操作方式
    • 使用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)

整合功能:

  1. 加载手机号码字典
  2. 为每个号码生成有效签名
  3. 调用接口获取加密数据
  4. 解密数据获取用户信息

5. 防御建议

5.1 服务端改进

  1. 增强签名机制

    • 使用更复杂的签名算法
    • 加入服务端独有的密钥
  2. 完善防重放

    • 使用时间戳+随机数组合
    • 缩短签名有效期
  3. 敏感数据保护

    • 避免在前端解密敏感数据
    • 必要数据应进行脱敏处理

5.2 前端防护

  1. 代码混淆

    • 使用高级混淆工具
    • 定期更新混淆方案
  2. 反调试措施

    • 检测调试器存在
    • 触发调试时采取防御行为
  3. 关键逻辑保护

    • 将关键逻辑移至Web Worker
    • 使用WebAssembly实现敏感操作

6. 总结

本案例展示了如何通过:

  1. 前端代码分析定位关键逻辑
  2. 动态调试理解签名生成机制
  3. 重放请求测试系统防御
  4. 将手工测试转化为自动化工具

最终实现了绕过参数签名和防重放机制,批量获取用户敏感信息的能力。这提醒我们前端安全同样重要,不能仅依赖参数签名等单一防御机制。

前端安全分析:绕过参数签名与防重放机制实战教学 1. 背景与发现 在金融行业某私测项目中,发现一个业务办理页面存在以下特征: 需要向客户发送短信验证码 响应报文中包含大段加密数据 全站并非全参数加密,加密参数可疑 篡改密文会导致"实名认证异常"提示 初步判断该密文涉及用户信息,且通过前端JS进行解密。 2. 漏洞分析 2.1 加密数据解密 通过分析前端JS代码,发现: 加密数据在前端进行解密 解密后的数据包含用户敏感信息(姓名、单位地址、家庭地址、身份证号码等) 2.2 参数签名机制 系统采用以下安全机制: 防篡改 :客户端对所有请求参数进行哈希计算,生成签名(sign) 防重放 :签名一次性使用,重复签名会被拒绝 签名流程: 客户端生成签名放入authorization头部 服务端基于相同信息生成签名 比较客户端和服务端签名 不同 → 参数被篡改 → 拒绝请求 相同 → 检查是否重复使用 重复 → 请求被重放 → 拒绝请求 不重复 → 处理请求 3. 绕过防御机制 3.1 识别签名关键点 通过Burp Suite测试发现: 修改PHONE_ NO参数会导致"参数签名异常"错误 重放相同请求会导致"条件不达标"(412 Precondition Failed)错误 authorization头部结构: 3.2 定位签名生成逻辑 通过前端代码分析: 全局搜索sign关键字,定位到1875行的 _e() 函数 该函数负责: 计算签名(s) 生成authorization值 3.3 动态调试签名生成 调试步骤: 在 _e() 函数入口和出口设置断点 观察调用参数和返回值 通过控制台测试不同参数: 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. 总结 本案例展示了如何通过: 前端代码分析定位关键逻辑 动态调试理解签名生成机制 重放请求测试系统防御 将手工测试转化为自动化工具 最终实现了绕过参数签名和防重放机制,批量获取用户敏感信息的能力。这提醒我们前端安全同样重要,不能仅依赖参数签名等单一防御机制。