发布时间:2026/7/27 11:17:29
逆向HmacSHA512动态签名:破解企业数据平台反爬机制实战 1. 项目概述当爬虫遇上动态加密请求头做爬虫的朋友尤其是和数据查询、企业信息这类网站打交道比较多的肯定对“某查查”这类平台不陌生。它们的数据价值高反爬措施也相应地非常严密。最近在分析其中一个数据接口时我发现它的请求头里藏着一个动态变化的加密参数核心算法是HmacSHA512。这不再是简单的token或者sign加个时间戳就能糊弄过去的了而是一种基于密钥的哈希消息认证码安全性很高。简单来说服务器和前端约定了一个密钥前端用这个密钥对特定的消息比如请求参数、时间戳等进行 HmacSHA512 计算生成一个唯一的、不可伪造的签名放在请求头里。服务器收到后用同样的密钥和规则再算一遍如果一致就放行否则直接拒绝。这种机制下你光知道加密算法是没用的核心在于找到那个用于计算的密钥以及生成签名的原始消息我们常说的“明文”是什么。这个实战的目标很明确逆向分析前端 JavaScript 代码定位到 HmacSHA512 加密函数找出其密钥和明文拼接逻辑最终在 Python 中复现整个签名生成过程让我们的爬虫程序能够自主构造出合法的请求头成功获取数据。整个过程就是一场典型的“猫鼠游戏”考验的是对前端代码逻辑的梳理能力和密码学知识的应用。2. 核心思路与逆向切入点分析面对一个经过混淆、压缩的复杂前端 JS 代码库直接“硬看”无异于大海捞针。我们需要一套系统的方法来缩小搜索范围快速定位目标。2.1 从网络请求入手确定攻击面一切逆向的开始都是浏览器开发者工具的 Network 面板。首先正常操作网站触发你想要抓取数据的那个 XHR 或 Fetch 请求。重点关注请求的Headers部分。以本次目标为例在请求头中我找到了一个名为X-Signature的字段它的值是一长串固定的 128 位十六进制字符串HmacSHA512 的结果就是 512 位即 64 字节用十六进制表示就是 128 个字符。同时请求头里通常还会伴随一个X-Timestamp字段。这几乎是一个明确的信号签名很可能由“时间戳其他信息”通过 HmacSHA512 生成。注意不同的网站签名参数名可能不同常见的有signature,sign,x-sign,authorization等。时间戳参数名也可能是timestamp,x-ts等。关键是要找到那对看起来像是“数据”和“其哈希签名”的字段。2.2 关键线索搜索与断点设置有了参数名我们就可以在 JS 代码里进行搜索了。全局搜索关键词在 Sources 面板下按CtrlShiftF打开全局搜索。首先搜索X-Signature和X-Timestamp看看它们在哪里被设置。很可能是在一个统一的请求拦截器或axios/fetch的请求配置函数里。搜索算法名称直接搜索HmacSHA512、CryptoJS.HmacSHA512如果用了 CryptoJS 库、createHmacNode.js 或 Web Crypto API 风格。如果代码混淆严重这些字符串可能被转义或拆分可以尝试搜索SHA512、Hmac等部分关键词。Hook 关键函数如果搜索无果说明函数名可能被混淆了。这时可以尝试“Hook”住设置请求头的函数。在 Console 中执行以下代码然后重新触发请求// 拦截所有请求头的设置操作 (function() { var originalSet XMLHttpRequest.prototype.setRequestHeader; XMLHttpRequest.prototype.setRequestHeader function(key, value) { console.log(Setting Header:, key, , value); if (key.toLowerCase().includes(sign)) { // 重点关注签名头 console.trace(Stack trace for sign header); // 打印调用栈 debugger; // 自动断点 } return originalSet.apply(this, arguments); }; })();当X-Signature被设置时debugger会触发断点此时调用栈Call Stack会清晰地展示出是哪个函数调用了它逆向之旅就从这里正式深入。2.3 逆向环境准备本地调试与代码格式化定位到关键的加密函数后你面对的很可能是一坨压缩到一行的代码。这时Chrome 开发者工具自带的“Pretty Print”功能那个{}图标就是你的救星。它能将混淆的代码格式化恢复一定的可读性。但更复杂的情况是代码可能被Webpack等打包工具模块化或者使用了自执行的函数闭包导致无法直接在一个文件里看到完整逻辑。这时你需要将代码导出到本地在 Sources 面板找到目标 JS 文件右键选择Save as...保存到本地。使用本地 IDE 分析用 VSCode、WebStorm 等打开利用其强大的搜索、跳转和代码折叠功能进行分析。对于特别复杂的混淆可以尝试使用de4js等在线或离线的反混淆工具进行初步处理但要注意过度反混淆可能会破坏代码逻辑。构建补环境调试最稳妥的方法是在 Node.js 环境中补全加密函数所依赖的浏览器环境如window,document,navigator等对象。这样你可以单独运行、修改和调试这个加密函数验证你的逆向结果。这是高阶逆向的必备技能。3. HmacSHA512 加密逻辑深度解析经过一番搜索和断点调试我们终于找到了加密的核心函数。假设我们找到的函数片段经过格式化后如下所示这是一个高度简化和模拟的例子真实代码会复杂得多function generateSignature(timestamp, path, queryString) { // 1. 拼接明文消息 var message v1|${timestamp}|${path}|${queryString}; // 2. 获取密钥密钥可能来自一个固定的字符串也可能由其他函数动态生成 var secretKey window._globalConfig.apiSecret; // 假设密钥存放在全局配置中 // 3. 使用 CryptoJS 进行 HmacSHA512 加密 var hash CryptoJS.HmacSHA512(message, secretKey); // 4. 将结果转换为十六进制字符串 var signature hash.toString(CryptoJS.enc.Hex); return signature; }让我们逐行拆解这个逻辑这直接关系到我们后续用 Python 复现的成功率。3.1 明文Message的拼接规则这是最容易出错的一步。message的拼接方式因网站而异但无外乎以下几种元素的排列组合API 版本如v1、v2可能硬编码在字符串里。时间戳通常是毫秒级或秒级时间戳。务必注意服务器使用的是秒还是毫秒这可以通过对比请求头中的X-Timestamp和当前时间推算出来。请求路径即 URL 的路径部分如/api/v4/company/search。注意是否包含开头的斜杠。查询字符串即?后面的部分如name测试page1。这里坑最多参数是否需要按字母顺序排序参数值是否需要做 URL 编码是编码前拼接还是编码后拼接空参数是否参与拼接是否包含?符号本身请求体对于 POST 请求消息体JSON 或 FormData可能也需要参与签名。通常是将其字符串化如JSON.stringify后拼接。分隔符常用|、、\n、:或者直接拼接。实操心得最可靠的方法是在 JS 代码里找到拼接message的那行代码用console.log打印出最终的message字符串。然后在 Python 里用同样的规则拼接确保两个字符串完全一致包括每一个空格和标点。你可以先写一个简单的 Node.js 脚本把关键函数抠出来运行打印中间变量进行验证。3.2 密钥Secret Key的寻找密钥是 Hmac 算法的灵魂。在上述例子中它看似从window._globalConfig.apiSecret获取。但在逆向中这个_globalConfig对象可能是在其他 JS 文件里定义或者通过一个复杂的函数计算得来。搜索字符串在全站 JS 代码中搜索apiSecret、secretKey、appSecret等关键词。跟踪变量在加密函数处打上断点然后观察secretKey这个变量的值。在 Chrome 的 Scope 面板或 Watch 面板里可以查看它的具体内容。如果它是一个变量可以右键点击选择 “Reveal in Sources panel” 来查看它在哪里被赋值。可能是计算值有些网站的密钥并非明文存储而是由appId、固定盐值salt和当前日期等元素通过某种哈希如 MD5计算得出。你需要逆向这个计算过程。3.3 加密库的识别前端实现 HmacSHA512 常见有以下几种方式CryptoJS最常用。特征是有CryptoJS.HmacSHA512调用或者先CryptoJS.HmacSHA512再.toString()。Web Crypto API现代浏览器原生支持。特征是用crypto.subtle.importKey,crypto.subtle.sign等函数代码看起来更“原生”和异步。自定义实现或小众库较少见需要你仔细分析其内部的哈希计算过程。识别出使用的库才能在用 Python 复现时选择对应的实现方式。CryptoJS 的 HmacSHA512 和 Python 的hmac.new(key, msg, hashlib.sha512).hexdigest()在结果上是标准且互通的前提是密钥和消息处理一致。4. Python 复现完整流程与代码实现假设我们已经通过逆向分析100% 确定了以下信息明文规则fv1|{timestamp}|{path}|{sorted_query_string}timestamp: 秒级时间戳。path: 请求路径如/api/v4/search。sorted_query_string: 将查询参数字典按 key 排序后拼接成key1value1key2value2的格式值需要经过 URL 编码。密钥一个固定的字符串例如this_is_my_secret_key_2024。加密方式CryptoJS.HmacSHA512。下面我们用 Python 来复现。4.1 环境准备与依赖安装确保你的 Python 环境已安装必要的库。我们主要使用hashlib和hmac它们是 Python 标准库的一部分无需额外安装。但为了处理 URL 编码和请求我们也会用到urllib和requests。# 主要用到的内置库无需安装 import hashlib import hmac import time from urllib.parse import quote, urlencode # 用于最终发送请求需要安装pip install requests import requests4.2 签名生成函数详解这是最核心的部分每一步都必须和前端逻辑严丝合缝。def generate_signature(secret_key: str, timestamp: int, path: str, params: dict) - str: 根据逆向分析的规则生成 HmacSHA512 签名。 Args: secret_key: 逆向得到的密钥字符串。 timestamp: 秒级时间戳。 path: API请求路径如 /api/v4/search。 params: 请求参数字典如 {name: 测试, page: 1}。 Returns: 128位的十六进制签名字符串。 # 1. 对参数进行排序并编码生成查询字符串 # 按照 key 的字母顺序排序 sorted_params sorted(params.items(), keylambda x: x[0]) # 将每个参数值进行 URL 编码。注意只编码 value不编码 key。 encoded_params [(k, quote(str(v), safe)) for k, v in sorted_params] # 拼接成 keyvalue... 的格式 query_string .join([f{k}{v} for k, v in encoded_params]) # 2. 按照既定规则拼接明文消息 (message) # 规则: v1|timestamp|path|query_string message fv1|{timestamp}|{path}|{query_string} print(f[DEBUG] 待签名的明文消息: {message}) # 调试时打印正式使用可去掉 # 3. 进行 HmacSHA512 计算 # 注意密钥和消息都需要转换为 bytes 类型 # 通常密钥是字符串直接 encode() # 如果前端密钥是 Base64 或 Hex则需要相应解码 key_bytes secret_key.encode(utf-8) msg_bytes message.encode(utf-8) # 使用 hmac 库进行计算 hmac_obj hmac.new(key_bytes, msg_bytes, hashlib.sha512) # 获取十六进制表示的摘要 signature hmac_obj.hexdigest() print(f[DEBUG] 生成的签名: {signature}) return signature关键点解析quote(str(v), safe): 这里使用urllib.parse.quote进行 URL 编码。safe参数表示不对任何字符保留即全部编码这通常符合前端encodeURIComponent的行为。务必确认前端使用的编码函数有时可能是encodeURI不编码/等字符。sorted(params.items()): 排序是保证拼接顺序一致的关键。前端可能不排序也可能按其他规则排序必须完全一致。f”v1|{timestamp}|{path}|{query_string}“: 这个格式模板必须和 JS 代码里的一模一样包括分隔符|。4.3 构造请求头并发送请求生成签名后将其与时间戳一同放入请求头然后发送请求。def make_signed_request(url: str, path: str, params: dict, secret_key: str): 构造带签名的请求并发送。 # 获取当前秒级时间戳 timestamp int(time.time()) # 生成签名 signature generate_signature(secret_key, timestamp, path, params) # 构造请求头 headers { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36, X-Timestamp: str(timestamp), # 注意头部的值通常是字符串 X-Signature: signature, # 可能还需要其他固定或动态的头如 Content-Type, Referer 等 Content-Type: application/json, } # 发送 GET 请求 (假设是 GET) response requests.get(url, paramsparams, headersheaders) # 如果是 POST可能需要将 params 放到 data 或 json 参数中 # response requests.post(url, jsonparams, headersheaders) print(f请求状态码: {response.status_code}) if response.status_code 200: print(f响应数据: {response.json()}) return response.json() else: print(f请求失败: {response.text}) return None # 使用示例 if __name__ __main__: # 替换成你逆向得到的真实密钥 SECRET_KEY this_is_my_secret_key_2024 # API 的基础 URL 和路径 BASE_URL https://api.example.com API_PATH /api/v4/search # 请求参数 query_params { keyword: 科技有限公司, page: 1, size: 20 } full_url BASE_URL API_PATH data make_signed_request(full_url, API_PATH, query_params, SECRET_KEY)5. 逆向与复现过程中的常见问题与排查技巧即使逻辑看起来完美复现在实际操作中依然会遇到各种问题。下面是我踩过的一些坑和对应的排查方法。5.1 签名验证失败原因分析与逐项核对当你的 Python 脚本生成的签名被服务器拒绝时请按照以下清单逐一核对时间戳不一致问题服务器可能要求毫秒级时间戳而你用了秒级或者存在时钟漂移。排查在浏览器中发起一次成功请求记录下X-Timestamp头的值。同时用 JavaScriptDate.now()打印一个时间戳。对比两者确定是秒还是毫秒。在 Python 中用int(time.time() * 1000)获取毫秒级时间戳。消息Message拼接不一致最常见问题这是 90% 失败的原因。多一个空格、少一个竖线、编码不一致、参数顺序不对都会导致最终的哈希值天差地别。排查黄金法则在 JS 加密函数里在return signature之前用console.log(‘message:’, message)和console.log(‘signature:’, signature)打印出明文和签名。在你的 Python 代码的generate_signature函数里也打印出拼接好的message。将两者进行逐字符对比。可以写一个小函数或者直接复制到文本比较工具里。确保完全一致。特别注意中文字符的编码。JS 的encodeURIComponent(‘测试’)会得到%E6%B5%8B%E8%AF%95Python 的quote(‘测试’)默认也是这个结果但要确认safe参数设置是否正确。密钥Key错误问题你以为的密钥可能不是最终用于计算的密钥。它可能被 Base64 解码过、被 Hex 解码过或者与其他字符串拼接过。排查在 JS 调试器中在计算 Hmac 的那一行打上断点查看传入CryptoJS.HmacSHA512的第二个参数即密钥的实际值和类型。如果它是CryptoJS.enc.Utf8.parse(“xxx”)的结果那它就是一个 WordArray 对象其本质是经过 UTF-8 编码的字节。在 Python 中我们直接用key.encode(‘utf-8’)即可对应。如果密钥是 Hex 或 Base64 字符串则需要先用bytes.fromhex()或base64.b64decode()处理。哈希算法或输出格式错误问题虽然说是 HmacSHA512但有没有可能中间还套了其他处理比如先 MD5 再 SHA512或者输出不是 Hex而是 Base64排查看 JS 代码里CryptoJS.HmacSHA512(...)之后调用了什么方法。.toString(CryptoJS.enc.Hex)是 Hex.toString(CryptoJS.enc.Base64)是 Base64。Python 中对应使用.hexdigest()或.digest()后再base64.b64encode()。5.2 高级技巧本地 Node.js 验证环境为了彻底隔离网络和环境变量问题最高效的方法是在本地 Node.js 环境中直接运行你从网站“抠”出来的、未经修改的加密函数。在浏览器 Sources 面板找到包含加密函数的整个代码块可能是一个闭包或模块将其复制到一个新的.js文件中。在这个文件末尾补上调用代码并打印结果。例如// 这是从网站复制过来的、包含 generateSignature 函数的代码... // ... // 这是你添加的测试代码 var testTimestamp 1712345678; var testPath /api/v4/search; var testParams {keyword: 测试, page: 1}; // 注意这里需要模拟出原网站获取密钥的环境比如 window._globalConfig // 如果密钥是写死的就直接赋值 window {}; // 简单补环境 window._globalConfig { apiSecret: this_is_my_secret_key_2024 }; var result generateSignature(testTimestamp, testPath, testParams); console.log(JS 计算结果:, result);在终端运行node your_test_file.js得到签名 A。用你的 Python 脚本使用相同的输入参数计算得到签名 B。对比 A 和 B。如果一致恭喜你Python 复现成功。如果不一致问题一定出在密钥、消息拼接或编码的细节上而算法本身没问题。你可以修改 JS 测试文件多打印一些中间变量与 Python 的中间变量对比。5.3 应对代码更新与反爬升级网站的反爬策略不是一成不变的。密钥轮换密钥可能会定期更换。如果你的脚本某天突然全部失效而消息逻辑没错首先要怀疑密钥变了。需要重新抓包、逆向定位新的密钥来源。算法升级可能从 HmacSHA512 升级到更复杂的算法或者加入随机盐salt、动态密钥。代码混淆加强函数名、变量名可能每次更新都变但核心逻辑通常不变。此时通过 Hook 请求头设置函数来定位入口点的方法依然有效。风控拦截即使签名正确频繁的、带有异常特征的请求如无头浏览器、固定 IP 高频访问也可能被风控系统拦截。需要合理设置请求间隔、使用代理 IP 池、模拟更真实的浏览器指纹如User-Agent、Accept-Language等头信息。逆向工程是一场持久战核心在于理解原理、耐心调试和严谨对比。每一次成功的解密不仅是为了拿到数据更是对前端安全机制和密码学应用的一次深刻理解。把每次遇到的坑和解决方案记录下来形成自己的知识库以后再遇到类似的加密解决起来就会快得多。

相关新闻

2026/7/27 11:12:29

文档下载困境的3种高效解决方案:kill-doc开源工具深度解析

文档下载困境的3种高效解决方案:kill-doc开源工具深度解析 【免费下载链接】kill-doc 看到经常有小伙伴们需要下载一些免费文档,但是相关网站浏览体验不好各种广告,各种登录验证,需要很多步骤才能下载文档,该脚本就是为…

2026/7/27 11:12:29

如何快速掌握Palworld存档编辑:3种简单方法告别存档损坏

如何快速掌握Palworld存档编辑:3种简单方法告别存档损坏 【免费下载链接】palworld-save-tools Tools for converting Palworld .sav files to JSON and back 项目地址: https://gitcode.com/gh_mirrors/pa/palworld-save-tools 你是否曾因Palworld存档损坏而…

2026/7/27 14:12:46

深入解析LM81硬件监控芯片:从原理到实战的完整指南

1. 项目概述与核心价值在服务器、工作站乃至高性能PC的运维和DIY领域,硬件监控一直是个既基础又关键的环节。想象一下,你精心搭建的机器,无论是承载着核心业务的服务器,还是渲染大作的工作站,其内部CPU的温度是否在安全…

2026/7/27 14:12:46

具身智能数据基础设施的技术架构与产业趋势分析

具身智能数据基础设施的技术架构与产业趋势分析2026年中期,具身智能产业正在经历一次深层的竞争逻辑转变。从技术验证阶段进入规模部署阶段后,产业竞争焦点正从硬件本体能力转向数据能力建设。行业测算数据显示,具身智能领域的数据需求正从数…

2026/7/27 14:12:46

nano-vLLM轻量级推理框架优化大模型部署实战

1. 项目背景与核心价值最近在优化大模型推理服务时,我发现nano-vLLM这个轻量级推理框架在资源受限场景下表现相当亮眼。相比传统方案,它通过连续批处理(Continuous Batching)和动态KV缓存管理,能在消费级显卡上实现接近…

2026/7/27 14:12:46

C++实战入门:从工具链配置到项目构建的工程化学习路径

1. 从“Hello World”到构建系统:C学习路径的重新审视 提到C,很多人的第一反应是“难”。指针、内存管理、模板、多继承……这些词汇堆砌起来,仿佛筑起了一道高墙。网上的教程多如牛毛,从“三天速成”到“百万字详解”&#xff0…

2026/7/27 14:07:46

改进boxinst_r50_fpn模型实现高效数字识别与定位

1. 数字识别与定位任务:Det改进实现boxinst_r50_fpn_ms-90k_coco模型训练 1.1. 模型概述 boxinst_r50_fpn_ms-90k_coco模型是基于Detectron2框架改进的数字识别与定位模型。这个模型的核心创新点在于将传统的两阶段检测流程优化为端到端的解决方案,显著…

2026/7/27 9:04:58

PDF合并与动态水印的工程化方案:2026国内免费工具实测对比

一、背景与测试方案 在实际项目交付中,PDF文件合并与版权保护水印的叠加是一个高频但容易被低估的技术需求。典型的处理链路涉及:多源PDF的文件流合并、页面级水印渲染(含透明度混合与图层叠加)、输出文件体积控制。看似简单的操作…

2026/7/27 0:01:12

xcku5p-ffvb676-2-i 设计 RoCEv2 时 constraints.xdc 配置依据核查记录

constraints.xdc 配置依据核查记录 被核查文件:fpga/vitis/xcku5p/build/constraints/constraints.xdc 目标板卡:RK-XCKU5P-F V1.2(搭载 xcku5p-ffvb676-2-i) 移植母本:fpga/pynq/rfsoc-pynq/build/constraints/constraints.xdc(NVIDIA Holoscan Sensor Bridge 参考工程)…

2026/7/27 0:01:12

TMS320C54x DSP内存映射与I/O模拟配置实战指南

1. 项目概述与核心价值在嵌入式系统开发,尤其是DSP这类资源受限、架构独特的处理器上,内存映射配置和I/O模拟是每个开发者都必须跨越的一道坎。这不仅仅是调试器里的几个菜单选项或命令行参数,它直接关系到你的程序能否在目标板上正确运行、能…

2026/7/27 3:13:33

3个高效策略:快速掌握Axure中文界面配置

3个高效策略:快速掌握Axure中文界面配置 【免费下载链接】axure-cn Chinese language file for Axure RP. Axure RP 简体中文语言包。支持 Axure 11、10、9。不定期更新。 项目地址: https://gitcode.com/gh_mirrors/ax/axure-cn 还在为Axure RP的英文界面感…