动态 Token、加密参数逆向全流程:从原理到实战破解

在 Python 网络爬虫开发中,动态 Token 和加密参数是网站反爬机制的 "核心防线"。无论是电商平台的商品价格、社交平台的接口数据,还是各类 API 的权限验证,都频繁使用这类技术阻止非法爬取。对于爬虫工程师而言,掌握动态 Token 与加密参数的逆向分析能力,是突破反爬限制、获取目标数据的关键。本文将从原理拆解、工具准备、逆向流程、实战案例四个维度,带你全面掌握这一核心技能。

一、核心概念:动态 Token 与加密参数是什么?

在开始逆向之前,我们首先要明确两个核心概念,理解其作用和本质:

1. 动态 Token:接口请求的 "临时通行证"

  • 定义:Token(令牌)是服务器生成的一串加密字符串,作为客户端与服务器通信的身份验证凭证。动态 Token 意味着每次请求或每隔一定时间,Token 会动态变化,无法通过固定值复用。
  • 常见类型
    • JWT(JSON Web Token):由 Header、Payload、Signature 三部分组成,常用于前后端分离项目的身份验证;
    • 时间戳 + 随机字符串组合 Token:如token=1695834256_7a5f9c3d2b8e10,通过时间戳保证时效性;
    • 服务器会话 Token:基于用户登录状态生成,存储在 Cookie 或 LocalStorage 中,超时自动失效。
  • 作用:防止请求伪造、验证请求合法性、限制接口访问频率。

2. 加密参数:隐藏关键信息的 "密码锁"

  • 定义:加密参数是客户端将原始数据(如用户 ID、请求参数、设备信息等)通过特定加密算法处理后,传递给服务器的参数。
  • 常见加密算法
    • 对称加密:AES、DES、3DES(加密解密使用同一密钥);
    • 非对称加密:RSA(公钥加密、私钥解密,常用于密钥交换);
    • 哈希算法:MD5、SHA-1、SHA-256(不可逆,常用于数据校验);
    • 自定义加密:基于基础算法的二次封装(如加盐哈希、字符移位、Base64 编码 + 加密组合)。
  • 作用:隐藏敏感数据、防止参数篡改、增加逆向难度。

二、逆向准备:必备工具清单

工欲善其事,必先利其器。逆向分析需要借助专业工具捕获请求、调试代码、破解加密逻辑,以下是核心工具推荐:

1. 网络请求捕获工具

  • Chrome DevTools(F12)
    • 核心功能:Network 面板捕获接口请求,查看 Request Headers、Form Data/Payload、Response 数据;
    • 关键用法:筛选 "XHR/Fetch" 类型请求,开启 "Preserve log" 保留历史请求,通过 "Initiator" 定位请求触发的 JavaScript 文件。
  • Fiddler
    • 核心功能:全局捕获 HTTP/HTTPS 请求,支持断点调试、请求重放、数据篡改;
    • 适用场景:需要捕获桌面应用、移动端 APP 请求时(需配置代理和证书)。
  • Mitmproxy
    • 核心功能:命令行版抓包工具,支持 Python 脚本扩展,可自动化处理请求(如批量修改参数、保存数据);
    • 适用场景:高级爬虫工程师,需自定义抓包逻辑时使用。

2. JavaScript 调试工具

  • Chrome DevTools Sources 面板
    • 核心功能:查看网站所有 JavaScript 文件,设置断点、单步调试、查看变量值;
    • 关键用法:通过 "Search" 搜索加密参数名(如 "token""sign""encryptData")定位加密函数;使用 "Scope" 面板查看函数执行时的局部变量和全局变量。
  • VS Code + 调试插件
    • 核心功能:将网站 JavaScript 文件保存到本地,通过 VS Code 调试器单步跟踪,支持更灵活的代码分析;
    • 适用场景:加密逻辑复杂,需要逐行分析代码时。

3. 加密算法辅助工具

  • CryptoJS:JavaScript 加密库,支持 AES、DES、MD5 等常见算法,可用于验证逆向的加密逻辑是否正确;
  • Online Crypto Tools :在线加密解密工具(如站长工具、Base64.cn),快速验证 MD5、Base64、AES 等算法结果;
  • Python 加密库:requests(请求接口)、pycryptodome(AES/RSA 加密解密)、hashlib(MD5/SHA 哈希)、base64(编码解码),用于将逆向得到的逻辑用 Python 复现。

4. 其他辅助工具

  • Node.js:运行 JavaScript 代码,验证加密函数的正确性(避免 Python 与 JavaScript 语法差异导致的问题);
  • JsonFormatter:在线 JSON 格式化工具,便于查看接口返回的 JSON 数据;
  • RegExr:正则表达式测试工具,用于提取 JavaScript 中的密钥、加密逻辑片段。

三、逆向全流程:从捕获到复现(通用步骤)

动态 Token 和加密参数的逆向分析遵循 "定位→调试→破解→复现" 的核心流程,以下是详细步骤,适用于绝大多数网站:

步骤 1:定位目标接口与加密参数

首先需要明确爬取的目标接口,以及接口中包含的动态 Token 或加密参数。

  1. 打开目标网站,触发数据加载(如点击按钮、滚动页面);
  2. 打开 Chrome DevTools(F12)→ Network → 筛选 "XHR/Fetch",找到返回目标数据的接口;
  3. 查看接口的 Request 信息:
    • 若为 GET 请求,加密参数可能在 URL 中(如https://api.example.com/data?token=xxx&sign=yyy);
    • 若为 POST 请求,加密参数可能在 Form Data(表单提交)或 Request Payload(JSON 格式)中;
  4. 记录加密参数名(如 token、sign、nonce、encryptData),以及是否有固定参数(如 appId、version)。

示例 :某接口 POST 请求的 Payload 如下,其中tokensign为加密参数,timestamp为时间戳:

json

复制代码
{
  "username": "test",
  "password": "123456",
  "timestamp": 1695834256,
  "token": "a7f9d2b4e83c0165978d3f2b1e4c6a89",
  "sign": "3e5f7d9b1c2a4e6f8d0b2c4a6e8f0d1b2c3a4e5f6"
}

步骤 2:查找加密参数的生成位置

通过接口的 "发起者" 或搜索功能,定位加密参数的生成代码:

  1. 在 Chrome DevTools 的 Network 面板中,找到目标接口,点击 "Initiator"(发起者),查看触发请求的 JavaScript 文件和行号;
  2. 若 "Initiator" 无法直接定位,切换到 Sources 面板,点击 "Search"(快捷键 Ctrl+Shift+F),输入加密参数名(如tokensign),搜索所有相关的 JavaScript 文件;
  3. 分析搜索结果,重点关注包含参数赋值、函数调用的代码(如var token = generateToken();var sign = getSign(params););
  4. 找到生成加密参数的核心函数(如generateToken()getSign()),这是逆向的关键。

技巧 :若搜索结果过多,可结合接口的请求方式(如 POST)、参数上下文(如timestamp常与sign一起生成)缩小范围。

步骤 3:调试加密函数,破解逻辑

找到加密函数后,通过断点调试分析函数的输入、处理过程和输出,破解加密逻辑:

  1. 在加密函数的关键位置设置断点(点击代码行号前的空白处,出现蓝色标记);
  2. 重新触发接口请求(如刷新页面、点击按钮),代码执行到断点时会暂停;
  3. 利用 Sources 面板的调试工具分析:
    • Watch :添加变量或表达式(如paramskey),实时查看其值;
    • Scope :查看当前函数的局部变量(Local)、全局变量(Global),重点关注密钥(如key = "abc123xyz")、加密算法(如AESMD5);
    • Step Over(F10):单步执行代码,观察变量的变化;
    • Step Into(F11) :进入函数内部,查看嵌套调用的逻辑(如encryptAES()的实现);
  4. 记录关键信息:
    • 加密算法(如 AES-128-CBC);
    • 密钥(key)、偏移量(iv,AES-CBC 模式需用到);
    • 数据处理方式(如参数排序、拼接、加盐);
    • 输出格式(如 Base64 编码、十六进制字符串)。

示例 :调试发现sign的生成逻辑为:

  1. 将请求参数(usernamepasswordtimestamp)按字典序排序;
  2. 拼接为字符串:password=123456&timestamp=1695834256&username=test
  3. 拼接固定密钥:password=123456&timestamp=1695834256&username=test&key=abc123xyz
  4. 对拼接后的字符串进行 SHA-256 哈希,得到sign值。

步骤 4:用 Python 复现加密逻辑

破解加密逻辑后,使用 Python 对应的加密库复现生成过程,确保生成的参数能通过服务器验证:

  1. 根据加密算法选择对应的 Python 库(如 AES 用 pycryptodome,SHA-256 用 hashlib);
  2. 严格按照调试得到的逻辑编写代码(注意参数排序、拼接方式、编码格式,如 UTF-8);
  3. 验证结果:将 Python 生成的参数与浏览器中捕获的参数对比,若一致则说明复现成功;
  4. 处理动态 Token 的特殊情况:
    • 若 Token 通过接口获取(如登录接口返回access_token),则先请求 Token 接口,再将 Token 带入目标接口;
    • 若 Token 基于时间戳、设备指纹生成,需在 Python 中模拟对应的生成逻辑(如获取当前时间戳、生成随机字符串)。

示例代码(复现 SHA-256 签名逻辑)

python

复制代码
import hashlib
import urllib.parse

def generate_sign(params, secret_key):
    # 1. 按字典序排序参数
    sorted_params = sorted(params.items(), key=lambda x: x[0])
    # 2. 拼接为URL编码格式的字符串
    encoded_params = urllib.parse.urlencode(sorted_params)
    # 3. 拼接密钥
    sign_str = f"{encoded_params}&key={secret_key}"
    # 4. SHA-256哈希
    sha256 = hashlib.sha256()
    sha256.update(sign_str.encode("utf-8"))
    return sha256.hexdigest()

# 测试
params = {
    "username": "test",
    "password": "123456",
    "timestamp": 1695834256
}
secret_key = "abc123xyz"
sign = generate_sign(params, secret_key)
print("生成的sign:", sign)
# 输出应与浏览器中捕获的sign一致

步骤 5:集成到爬虫,测试验证

将复现的加密逻辑集成到爬虫代码中,发起请求并验证是否能成功获取数据:

  1. 构造完整的请求参数(包含动态 Token、加密参数、其他必要参数);
  2. 设置正确的请求头(如 User-Agent、Referer、Cookie,需与浏览器一致);
  3. 发起请求,查看响应状态码和响应数据:
    • 若状态码为 200 且返回目标数据,说明逆向成功;
    • 若状态码为 401(未授权)、403(禁止访问),可能是 Token 过期、签名错误或请求头不完整,需重新检查加密逻辑和请求配置;
  4. 处理异常情况:如 Token 有效期较短,需定时刷新;加密参数变化时,需重新逆向更新逻辑。

四、实战案例:破解某电商平台动态 Token 与 AES 加密参数

以下以某电商平台的商品价格接口为例,完整演示逆向流程:

1. 场景分析

目标接口:https://api.shop.com/api/goods/price(POST)请求 Payload:

json

复制代码
{
  "goodsId": "123456",
  "timestamp": 1695834567,
  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "encryptData": "f8d2b4e6a8c013579f2d4b6a8c0e2f4a..."
}

其中token为 JWT 令牌,encryptData为 AES 加密的商品 ID 和时间戳。

2. 逆向过程

步骤 1:定位加密函数
  • 搜索encryptData,找到生成代码:var encryptData = aesEncrypt(JSON.stringify({goodsId: goodsId, timestamp: timestamp}));
  • 定位aesEncrypt函数,发现其定义在utils.js文件中:

javascript

复制代码
function aesEncrypt(data) {
  var key = CryptoJS.enc.Utf8.parse("abcdef1234567890"); // 密钥(16位)
  var iv = CryptoJS.enc.Utf8.parse("0987654321fedcba"); // 偏移量(16位)
  var encrypted = CryptoJS.AES.encrypt(data, key, {
    iv: iv,
    mode: CryptoJS.mode.CBC,
    padding: CryptoJS.pad.Pkcs7
  });
  return encrypted.ciphertext.toString(CryptoJS.enc.Base64);
}
步骤 2:破解 JWT Token
  • 搜索token,发现其通过登录接口/api/user/login返回,有效期 2 小时;
  • JWT 结构解析:Header(算法:HS256)、Payload(包含 userId、exp 过期时间)、Signature(密钥:shop_secret_key)。
步骤 3:Python 复现

python

复制代码
import requests
import hashlib
import base64
import json
from datetime import datetime, timedelta
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad

# 1. JWT Token生成(模拟登录后获取,此处直接生成)
def generate_jwt(user_id, secret_key):
    # Header
    header = {"alg": "HS256", "typ": "JWT"}
    header_b64 = base64.urlsafe_b64encode(json.dumps(header).encode()).decode().rstrip("=")
    # Payload(exp为过期时间,当前时间+2小时)
    exp = int((datetime.now() + timedelta(hours=2)).timestamp())
    payload = {"userId": user_id, "exp": exp}
    payload_b64 = base64.urlsafe_b64encode(json.dumps(payload).encode()).decode().rstrip("=")
    # Signature
    signature = hashlib.sha256(f"{header_b64}.{payload_b64}".encode() + secret_key.encode()).digest()
    signature_b64 = base64.urlsafe_b64encode(signature).decode().rstrip("=")
    return f"{header_b64}.{payload_b64}.{signature_b64}"

# 2. AES加密(encryptData生成)
def aes_encrypt(data, key, iv):
    key_bytes = key.encode("utf-8")
    iv_bytes = iv.encode("utf-8")
    cipher = AES.new(key_bytes, AES.MODE_CBC, iv_bytes)
    encrypted_bytes = cipher.encrypt(pad(data.encode("utf-8"), AES.block_size))
    return base64.b64encode(encrypted_bytes).decode()

# 3. 爬虫主逻辑
def crawl_goods_price(goods_id):
    # 配置信息(从逆向中获取)
    secret_key_jwt = "shop_secret_key"
    aes_key = "abcdef1234567890"
    aes_iv = "0987654321fedcba"
    user_id = "789"  # 模拟登录后的用户ID
    
    # 生成参数
    timestamp = int(datetime.now().timestamp())
    token = generate_jwt(user_id, secret_key_jwt)
    encrypt_data = aes_encrypt(json.dumps({"goodsId": goods_id, "timestamp": timestamp}), aes_key, aes_iv)
    
    # 构造请求
    url = "https://api.shop.com/api/goods/price"
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36",
        "Content-Type": "application/json"
    }
    data = {
        "goodsId": goods_id,
        "timestamp": timestamp,
        "token": token,
        "encryptData": encrypt_data
    }
    
    # 发起请求
    response = requests.post(url, headers=headers, json=data)
    if response.status_code == 200:
        return response.json()
    else:
        return f"请求失败:{response.status_code}"

# 测试
if __name__ == "__main__":
    result = crawl_goods_price("123456")
    print("商品价格数据:", result)

3. 验证结果

运行代码后,若返回如下响应,说明逆向成功:

json

复制代码
{
  "code": 200,
  "msg": "success",
  "data": {
    "goodsId": "123456",
    "price": 99.9,
    "stock": 1000
  }
}

五、常见问题与应对技巧

在逆向过程中,经常会遇到各种反制措施,以下是高频问题及解决方案:

1. JavaScript 代码混淆(变量名加密、代码压缩)

  • 现象 :加密函数的变量名是乱码(如ab_0x123456),代码无换行、无注释,难以阅读;
  • 应对技巧
    • 使用 Chrome DevTools 的 "Pretty Print"({} 按钮)格式化代码,自动换行和缩进;
    • 重命名变量和函数(右键变量名→Rename),将乱码变量改为有意义的名称(如keyiv);
    • 借助在线反混淆工具(如jsnice.org)还原变量名和代码结构。

2. 密钥隐藏(动态生成密钥、从服务器获取密钥)

  • 现象:调试时未找到固定密钥,密钥通过其他接口请求、设备指纹生成或藏在 DOM 元素中;
  • 应对技巧
    • 搜索密钥相关的关键词(如keysecrettoken),查看是否有接口返回密钥;
    • 检查 DOM 元素(Sources→Elements),是否有隐藏的meta标签或script标签存储密钥;
    • 若密钥动态生成(如基于设备 ID),在 Python 中模拟设备 ID 的生成逻辑。

3. 调试断点失效(代码动态加载、反调试)

  • 现象:设置断点后,代码执行时未暂停,或出现 "Debugger statement detected" 提示;
  • 应对技巧
    • 禁用浏览器的反调试:在 Chrome DevTools→Settings→Debugger→取消勾选 "Disable JavaScript breakpoint debugging";
    • 对于动态加载的代码(如通过evaldocument.write加载),在代码执行前设置 "XHR Breakpoints"(拦截 JS 文件请求);
    • 移除代码中的debugger语句(搜索debugger,替换为空字符串)。

4. 加密参数频繁变化(服务器更新加密逻辑)

  • 现象:之前复现的代码突然失效,接口返回 403 或参数错误;
  • 应对技巧
    • 重新捕获请求,对比新旧参数的差异;
    • 重点查看加密函数是否有修改(如密钥变更、算法调整);
    • 编写自适应代码,预留加密逻辑的扩展接口(如将密钥、算法参数配置在外部文件中)。

六、合规与伦理提醒

逆向工程是一把 "双刃剑",在使用该技术时,必须遵守以下原则:

  1. 合法合规:仅对公开可访问的网站进行逆向,不得破解付费内容、隐私数据或涉及商业机密的系统;
  2. 尊重 robots.txt 协议:虽然动态 Token 反爬通常不遵循 robots.txt,但应避免对网站造成服务器压力(如控制请求频率);
  3. 不用于恶意用途:不得利用逆向得到的逻辑进行刷量、爬虫攻击、数据窃取等违法活动;
  4. 保护知识产权:网站的加密逻辑属于知识产权,不得将逆向得到的代码用于商业盈利或公开传播。

七、总结

动态 Token 与加密参数的逆向分析,核心是 "定位 - 调试 - 复现" 的闭环流程。掌握这一技能,需要熟悉 JavaScript 代码结构、常见加密算法原理和调试工具的使用,同时具备耐心和逻辑分析能力。随着网站反爬技术的不断升级,逆向过程可能会遇到各种挑战,但只要掌握核心方法,不断积累实战经验,就能突破大多数反爬限制。

相关推荐
qq_17082750 CNC注塑机数采40 分钟前
【Python TensorFlow】 TCN-GRU时间序列卷积门控循环神经网络时序预测算法(附代码)
python·rnn·神经网络·机器学习·gru·tensorflow·tcn
java1234_小锋1 小时前
基于Python深度学习的车辆车牌识别系统(PyTorch2卷积神经网络CNN+OpenCV4实现)视频教程 - 切割车牌矩阵获取车牌字符
python·深度学习·cnn·车牌识别
u***28471 小时前
Python连接SQL SEVER数据库全流程
数据库·python·sql
测试19981 小时前
接口测试工具之postman详解
自动化测试·软件测试·python·测试工具·测试用例·接口测试·postman
q***57501 小时前
问题:Flask应用中的用户会话(Session)管理失效
后端·python·flask
青瓷程序设计1 小时前
海洋生物识别系统【最新版】Python+TensorFlow+Vue3+Django+人工智能+深度学习+卷积神经网络算法
人工智能·python·深度学习
小邓   ༽1 小时前
C语言课件(非常详细)
java·c语言·开发语言·python·eclipse·c#·c语言课件
闲人编程2 小时前
Django中间件开发:从请求到响应的完整处理链
python·中间件·性能优化·django·配置·codecapsule
执笔论英雄2 小时前
【RL】Slime异步 routout 过程7 AsyncLoopThread
开发语言·python