深度解析:JS逆向破解报销发票系统的数据抓取技术

一、技术背景与场景分析

1.1 报销发票系统的技术特征

现代报销系统普遍采用前后端分离架构,前端通过Vue/React构建动态界面,后端采用Spring Cloud微服务架构。数据交互依赖加密的JSON格式请求,关键字段如发票号码、金额、开票日期等均经过非对称加密处理。

典型请求示例:

  1. // 加密请求体示例
  2. const encryptedData = {
  3. cipherText: "a1b2c3...", // AES加密后的数据
  4. iv: "d4e5f6...", // 初始化向量
  5. keyId: "pubKey_2023" // 公钥标识
  6. }

1.2 JS逆向的必要性

传统爬虫直接请求API接口会触发WAF防护,返回403错误。通过逆向分析前端JS代码,可破解:

  • 动态生成的加密参数(如token、sign)
  • 请求时间戳的校验逻辑
  • 参数排序规则(如按字段名ASCII码排序)

二、核心逆向技术实现

2.1 动态参数解密流程

2.1.1 加密函数定位

使用Chrome DevTools的Source面板,通过XHR断点定位加密函数。典型特征:

  • 包含CryptoJS、WebCrypto等加密库调用
  • 存在encryptsign等关键字
  • 输入为明文数据,输出为Base64字符串
  1. // 示例加密函数(混淆后)
  2. function _0x1a2b3c(data) {
  3. const _0x4d5e = CryptoJS.AES.encrypt(
  4. JSON.stringify(data),
  5. _0x6f7g['key'],
  6. { iv: _0x6f7g['iv'] }
  7. ).toString();
  8. return _0x4d5e;
  9. }

2.1.2 密钥提取技术

密钥获取的三种途径:

  1. 硬编码密钥:直接搜索new CryptoJS.enc.Utf8.parse('...')
  2. 动态生成密钥:跟踪window._config等全局变量
  3. 非对称加密:通过RSA算法解密服务端返回的公钥
  1. // RSA公钥提取示例
  2. const publicKey = `-----BEGIN PUBLIC KEY-----
  3. MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC...`;

2.2 请求头构造技术

2.2.1 核心Header字段

字段名 作用 逆向方法
X-Token 身份验证 跟踪localStorage.getItem
X-Sign 请求签名 定位sign生成函数
X-Timestamp 时间戳校验 模拟new Date().getTime()

2.2.2 签名算法破解

常见签名算法实现模式:

  1. // MD5签名示例
  2. function generateSign(params) {
  3. const sortedParams = Object.keys(params).sort().map(key =>
  4. `${key}=${params[key]}`
  5. ).join('&');
  6. return CryptoJS.MD5(sortedParams + '_salt').toString();
  7. }

三、反爬策略应对方案

3.1 常见防护机制

  1. 行为检测:鼠标轨迹、点击间隔等
  2. 设备指纹:Canvas指纹、WebGL指纹
  3. 频率限制:IP级/账号级限流

3.2 破解技术方案

3.2.1 动态代理池

  1. // 代理切换逻辑示例
  2. const proxies = [
  3. { host: '1.1.1.1', port: 8080 },
  4. { host: '2.2.2.2', port: 8080 }
  5. ];
  6. function getProxy() {
  7. return proxies[Math.floor(Math.random() * proxies.length)];
  8. }

3.2.2 请求头随机化

  1. // 随机User-Agent生成
  2. const userAgents = [
  3. 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)...',
  4. 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)...'
  5. ];
  6. function randomUA() {
  7. return userAgents[Math.floor(Math.random() * userAgents.length)];
  8. }

四、法律风险与合规建议

4.1 法律边界分析

根据《网络安全法》第二十七条:

  • 禁止非法获取计算机信息系统数据
  • 禁止提供侵入、非法控制计算机信息系统的程序

4.2 合规数据采集方案

  1. 官方API接入:优先使用系统开放的API接口
  2. 用户授权采集:通过OAuth2.0获取用户授权
  3. 数据脱敏处理:对敏感字段进行哈希处理

五、完整实现示例

5.1 环境准备

  1. # Node.js环境依赖
  2. npm install crypto-js jsdom axios

5.2 核心代码实现

  1. const CryptoJS = require('crypto-js');
  2. const axios = require('axios');
  3. // 密钥配置(需逆向获取)
  4. const config = {
  5. key: CryptoJS.enc.Utf8.parse('1234567890abcdef'),
  6. iv: CryptoJS.enc.Utf8.parse('abcdef1234567890')
  7. };
  8. // 加密函数
  9. function encryptData(data) {
  10. return CryptoJS.AES.encrypt(
  11. JSON.stringify(data),
  12. config.key,
  13. { iv: config.iv }
  14. ).toString();
  15. }
  16. // 请求构造
  17. async function fetchInvoiceData(invoiceNo) {
  18. const encrypted = encryptData({
  19. invoiceNo: invoiceNo,
  20. timestamp: Date.now()
  21. });
  22. const response = await axios.post('https://api.example.com/invoice', {
  23. encryptedData: encrypted
  24. }, {
  25. headers: {
  26. 'X-Token': 'user_token_123',
  27. 'X-Sign': generateSign({ invoiceNo })
  28. }
  29. });
  30. return response.data;
  31. }
  32. // 签名生成(示例)
  33. function generateSign(params) {
  34. const str = Object.keys(params).sort().map(k =>
  35. `${k}=${params[k]}`
  36. ).join('&');
  37. return CryptoJS.MD5(str + '_secret').toString();
  38. }

六、技术演进趋势

  1. WebAssembly防护:将核心加密逻辑编译为WASM
  2. TLS指纹识别:通过JS检测客户端TLS配置
  3. AI风控系统:基于用户行为的实时风险评估

建议持续关注:

  • Chrome DevTools的新调试功能
  • 加密算法的硬件加速实现
  • 反爬技术的机器学习应用

本文提供的技术方案需严格遵守法律法规,建议在获得明确授权的前提下进行技术验证。实际开发中应建立完善的错误处理机制和日志系统,确保数据采集的稳定性和可追溯性。