资讯动态

从抓包改参数到签名校验:请求重放实战指南

发布时间:2026/9/16 16:20:19 来源:尧图企业网站定制
前端明明只允许输入 1 到 99 的数字我把抓包拿到的请求参数改成 5000 重发过去服务端照样接受了。这一幕让我对请求重放这件事彻底上了心——只要请求还在走 HTTP抓到之后改参数、重发、看响应这套流程就能把前端校验、后端校验、签名机制全都扒得一清二楚。这篇内容围绕请求重放和签名接口展开覆盖抓包工具选型、改参数重发的完整链路、签名接口怎么处理以及我在实操里踩过的各种坑。适合刚接触抓包的开发、测试和安全初学者也适合想搞明白签名校验机制原理的读者。读完后你可以根据实际情况自己复现这套操作不是看个热闹。1. 请求重放到底在解决什么问题1.1 我为什么开始折腾请求重放做后端接口联调的时候最烦听到前端一句话“页面这边只能传固定的参数别的我生成不了。” 这句话听起来合理但后端接口真的只处理这一种参数吗没人知道。前端有下拉框限制、有必填校验、有按钮置灰但这些都是浏览器层面的表现请求一旦发出后端看到的只是一个个键值对和 JSON 结构。我第一次做请求重放就是为了验证“前端拦住的参数后端是不是也拦住了”。那是一个订单数量的字段前端限制 1 到 99我抓包把数量改成 -1、改成 0、改成 999后端居然全收了。最后下订单数量为 -1 居然真的算出了负数金额这一条 bug 放到线上就是资损级别。从那以后我把请求重放当成了一个常规检测手段凡是前后端联调的接口先用抓包工具把能改的参数都改一遍看后端到底校验了什么。这也引出了一个很核心的结论——前端限制只是交互设计后端校验才是安全边界。1.2 重放技术在什么场景下真正有用请求重放不是渗透测试的专属技能它在我日常工作中出现的频率远比你想象的高接口联调和回归测试前端不方便构造异常数据抓包改参数直接造省去大量页面操作。安全测试授权范围内验证越权、参数篡改、重放攻击是否真实存在是提交漏洞报告前的必备动作。批量数据的补救与订正有的管理后台没有批量接口抓包拿到单个请求的完整结构用脚本循环重放相当于自己写了个一次性批量工具。第三方接口的逆向学习对接不熟悉的第三方 API 时直接抓包看真实请求比看文档更直观文档里没写的字段抓包能看到。接口幂等性验证同一个订单号重复支付、同一个流水号重复提交这些操作如果不用重放工具纯手工可能要点击几十次。但要注意这个技能是把双刃剑。只能在你自己有权限、有授权的系统上测试。把请求重放用到别人的系统上性质就变成攻击了这一点必须拎清楚。1.3 请求重放的本质HTTP 请求是可复制的HTTP 协议本身是无状态的服务端区分“这是不是同一个请求”依赖的只是请求头里的 Cookie、Authorization、时间戳、随机数这些字段。也就是说一个请求只要还没过期你把它原封不动地发十遍服务端大概率会处理十遍。改参数重放的逻辑就建立在这个基础上HTTP 请求是一份可以复制、修改、重新提交的数据你改掉其中某个字段再发出去就像写了一封新的信塞进同一个信封。信封的邮戳和发件人信息都是原来的收件人无法从协议层面判断这封信到底是不是客户端主动发起的。这里面有一个很重要的点改参数重放不等同于模拟真实用户操作。真实用户操作会产生新的页面状态、新的 token、新的交互上下文而重放只是绕过了页面直接让服务端执行某段逻辑。所以服务端如果做了状态校验、时间戳校验、随机数校验重放就会比正常操作更容易失败这也是后面签名接口那么难搞的根源。2. 工具选型Fiddler、Charles、Burp Suite 怎么挑2.1 三类工具的定位不同做请求重放工具选错了会绕很多弯路。先看主流的几类工具定位核心能力学习成本FiddlerWindows 平台的 HTTP 调试代理断点修改、Composer 重放、AutoResponder低Charles跨平台 HTTP 调试代理Breakpoints、Rewrite、Repeat、手机抓包低Burp SuiteWeb 安全测试平台Repeater、Intruder、Proxy 拦截改包中curl命令行请求工具快速重放单个请求、配合脚本批量低Python requests / mitmproxy脚本化请求与抓包自动化重放、请求改写、流量分析中Fiddler 和 Charles 的定位更像“调试工具”日常开发、联调、查接口问题非常顺手。Burp Suite 是“安全测试工具”里面 Repeater 的重放体验比前两者要精细得多改包、看响应、对比请求差异都做得更专业。curl 则适合快速验证和脚本化很多时候我抓包后直接复制成 curl 命令改个参数就扔到命令行里跑。2.2 从场景反推工具别从工具出发做场景新手最容易犯的错是“先学会一个工具再拿它干所有事”。实际工作里应该是反过来先想清楚这个请求我要怎么改、改多少次再决定用哪个工具。只是单个请求改参数重发一次用 Fiddler 的 Composer 或者 Charles 的 Repeat 就够了。操作链路短开代理、抓包、拦截、重放不需要额外学习概念。要做参数枚举或者批量重放比如数量从 1 试到 100或者用不同用户身份重放同一接口Burp Suite 的 Repeater 和 Intruder 是更合适的选择。Intruder 可以自动把某个参数替换成字典里的值省去手工一次次改参数的时间。要写自动化回归脚本那工具本身就不重要了直接导出请求记录用 Python requests 或者 curl 脚本去跑。接口变更时改脚本比在 GUI 工具里点来点去效率高得多。要抓手机 App 的请求Fiddler 和 Charles 都支持设置代理手机连上同一个局域网把代理指到电脑端口再装上对应的 HTTPS 证书就可以看到明文请求。2.3 我日常的抓包重放工作流我自己的习惯是Fiddler 抓包看全貌Burp Repeater 做重放Python 脚本做批量。理由很简单Fiddler 在 Windows 上对系统流量接管得干净抓包速度快Burp Repeater 改参数和看响应都清晰适合逐条验证一旦验证通过发现这个接口需要大量重复请求就写脚本自动化。这里顺便说个 curl 的实用技巧。很多抓包工具支持直接把请求复制成 curl 命令复制出来的命令长这样curl https://api.example.com/order/create \ -H Content-Type: application/json \ -H Cookie: sessionidabc123 \ --data-raw {goods_id:1001,num:1}想改参数重发直接改--data-raw里的 JSON 就行。-k参数可以忽略 HTTPS 证书校验-L参数跟随重定向这两个参数在做快速验证的时候很常用curl -k -L https://api.example.com/order/create \ -H Content-Type: application/json \ -H Cookie: sessionidabc123 \ --data-raw {goods_id:1001,num:-1}3. 改参数重发的完整实操链路3.1 拿到请求后先做三步不要急着改抓到请求后第一件事不是改参数而是先把请求拆开看清楚。一个普通 HTTP 请求里有三块内容请求方法和路径POST /order/createGET /user/info。改参数前先确认方法改没改比如原本是 POST你重放时用了 GET大部分后端会直接 404 或 405。请求头和 CookieCookie 里通常带着会话凭证Authorization 头里带着 token。重放时这些信息必须原样带上少一个都可能被服务端当作未登录请求。请求体表单格式还是 JSON 格式字段名是否大小写敏感嵌套结构是否完整。很多接口对请求体格式非常敏感少一个括号都不行。看明白之后再判断哪些参数值得改、改成什么值。不是所有参数都需要动先改业务字段比如数量、金额、用户 ID、订单状态而那些 token、时间戳、签名字段往往是重放的难点需要单独处理。3.2 用工具断点与重放的具体操作以 Fiddler 为例它的 Composer 功能可以直接重放请求。操作路径是抓到请求后右键选择Replay或Edit in Composer请求会自动带进 Composer 面板。在这个面板里你可以任意修改请求头、URL、请求体改完点Execute就完成了一次重放。想要更精细地控制可以使用断点功能。Fiddler 的命令行里输入bpu /api/order/create就能把所有发往这个路径的请求卡在断点上此时请求还没发送到服务端你可以修改请求体改完再放行。这种方式比在 Composer 里改更贴近真实场景——你是在“客户端原本要发的请求”基础上改的而不是凭空构造一个新请求。Burp Suite 的操作又不一样抓到请求后右键Send to Repeater左边是请求原文右边是响应结果。你可以任意修改左边请求的任何部分点Send就能看到修改后的响应。Repeater 最大的优势是改一次发一次方便逐条比对不同参数对应的服务端返回差异。以改订单数量为例原请求体是{goods_id:1001,num:1}你在 Repeater 里改成{goods_id:1001,num:-1}发送后看服务端是不是返回了成功。这时候你就能确定后端到底有没有对num字段做正数校验。用同样的方法把num改成字符串abc、改成超大数99999999、改成小数1.5一次重放就是一次测试用例。3.3 用脚本把重放变成自动化当你要重放的不再是单个请求而是几十个不同参数组合时GUI 工具点起来就很累了。这时候我会把请求转成 Python 脚本。步骤很简单先在抓包工具里复制请求为 cURL然后用 Python 重写。import requests import json url https://api.example.com/order/create headers { Content-Type: application/json, Cookie: sessionidabc123, } base_data { goods_id: 1001, num: 1, } test_values [-1, 0, 1, 99, 100, 99999, abc, 1.5] for value in test_values: data base_data.copy() data[num] value resp requests.post(url, headersheaders, jsondata) print(fnum{value!r} - status{resp.status_code}, body{resp.text[:200]})这段代码把不同参数值循环重放每个响应都打印出来。跑完一轮后端对num字段的全部校验逻辑就一目了然了。比起在工具里手动点脚本的可复现性和可维护性都高出一个量级。不过这里有个前提如果接口带了签名上面的脚本发出去大概率全部失败。原因很简单你改了num但签名还是基于原来num1算出来的服务端一验签就发现参数被人动过。这就引出了下一个重头戏——签名接口怎么处理。4. 签名接口怎么处理别硬刚逻辑先理清签名链路4.1 签名接口和普通接口的本质区别普通接口请求体里只有业务参数服务端校验完参数就直接处理。签名接口则不然它除了业务参数之外还会带一个sign字段。这个sign是由所有参数拼接后通过某种算法计算出来的摘要值密钥只有客户端和服务端知道。服务端收到请求后会用同样的算法、同样的密钥、同样的参数集合重新计算一次 sign如果和请求里带的 sign 不一致直接拒绝处理。这意味着什么意味着你改任何一个业务参数sign 都会对不上。改参数后必须同步重算签名否则请求就是废的。这里需要区分一个概念签名解决的是“参数有没有被篡改”的问题而不是“请求是不是重复”的问题。真正防重放通常靠时间戳和 nonce一次性随机数签名和防重放是两个独立的机制但实践中它们往往同时出现在一个接口里。4.2 常见的签名计算方式长什么样不同团队的安全水平差异很大签名实现方式也各不相同但核心套路基本就下面几种签名方式计算逻辑特点MD5 拼接md5(param1value1param2value2keysecret)简单但可预测最常见HMAC-SHA256hmac_sha256(key, param_string)密钥参与哈希运算安全性更高非对称签名客户端用私钥签名服务端用公钥验签安全性最高客户端私钥不可泄露混合方式参数排序 时间戳 nonce 密钥一起参与计算防篡改 防重放以最典型的 MD5 拼接为例我模拟一下签名计算的代码逻辑。假设请求参数是goods_id1001、num1约定的密钥是abc123签名的计算方式是import hashlib def calc_sign(params: dict, key: str) - str: # 1. 按 key 排序参数 sorted_params sorted(params.items()) # 2. 拼接成字符串 raw .join(f{k}{v} for k, v in sorted_params) # 3. 加上密钥 raw_with_key f{raw}key{key} # 4. 计算 md5 return hashlib.md5(raw_with_key.encode(utf-8)).hexdigest() params {goods_id: 1001, num: 1} print(calc_sign(params, abc123)) # 输出类似: 9f2b4d8c...看到没有sign的生成严重依赖参数。你把num从 1 改成 -1重新计算的 sign 就和原来完全不一样。如果只改num不带新 sign服务端拿到后一算对不上立刻拒绝。4.3 处理签名接口的三条路线按优先级排处理签名接口很多人第一反应是“反编译 App”、“逆向算法”但这个思路并不是最优解。我按实际操作的性价比排了三条路线路线一从请求发起端找签名逻辑重算新签名这是最正统也最常用的方法。签名算法一定存在于客户端代码里要么在前端 JS 里要么在 App 的 so 库里。对于 Web 应用直接在浏览器开发者工具里搜关键词sign、md5、sha256、secret、encrypt大概率能定位到签名函数。找到算法后用 Python/JS 复现一遍改完参数重新生成 sign 再重放。路线二Hook 前端的签名函数让客户端替你生成合法签名如果不方便复现算法可以换个思路——不自己算而是让客户端自己算。比如 Web 端可以用油猴脚本在页面加载后 hook 住签名函数App 端可以用 Frida 这类动态插桩工具把签名函数包一层参数变了它照样算出新签名。这个思路的精髓在于你不需要知道签名算法内部怎么实现你只需要保证修改参数后调用签名函数的时机仍然触发。路线三只改不影响签名的字段有的接口签名校验范围只覆盖业务参数不覆盖 Cookie、traceId、设备号这类元数据。这种情况下你完全可以不动 sign只改那些不影响签名的字段。比如把订单号相关的参数保留改请求头的 User-Agent、改来源参数看服务端返回是否变化。这个方法局限性大但胜在改动最小有时候验收测试只需要验证“某个字段改了对不对”并不需要深究整个签名机制。这里必须强调以上的处理方式只适用于你自己有权限测试的系统或者在漏洞披露平台上经过授权的测试目标。越过授权范围去分析别人的签名接口性质等同于攻击请务必守住边界。4.4 签名重放实操示例从抓包到重新签名给你一个完整的实操链路场景是某后台管理系统的登录接口带了签名我想验证登录接口在用户名参数上是否存在逻辑问题。第一步抓包。用 Fiddler 监听浏览器请求找到登录接口的 POST 请求请求体长这样usernameadminpassword123456timestamp1699999999signa1b2c3d4e5...第二步找签名算法。在浏览器开发者工具的 Sources 面板里全局搜索sign很快定位到一截 JSfunction getSign(params, secret) { var keys Object.keys(params).sort(); var raw keys.map(k k params[k]).join(); return md5(raw key secret); }这里密钥secret的值就在 JS 里写死了比如abc123。第三步用 Python 复现这套签名逻辑。注意算法里有两个细节参数要排序、密钥是拼接在最后的。import hashlib import time def calc_sign(username, password, timestamp, secretabc123): params { username: username, password: password, timestamp: timestamp, } # 与 JS 保持一致的排序和拼接 sorted_params sorted(params.items()) raw .join(f{k}{v} for k, v in sorted_params) return hashlib.md5((raw key secret).encode()).hexdigest() # 测试重放 timestamp int(time.time()) sign calc_sign(admin, wrongpass, timestamp) print(sign)第四步把重放的请求组装好带上新的时间戳和新的签名一起发出去。这个请求在服务端验签能通过因为参数、时间戳、签名三者是配套的。第五步验证结果。如果服务端仍然返回成功说明登录接口对密码错误没做有效拦截如果返回签名错误说明算法还有细节没对齐回头检查字段类型、编码方式、是否包含额外参数。核心心得签名算法的复现坑几乎都在细节上。参数顺序错了、某个字段拼成了字符串而不是数字、MD5 结果大小写不对、多了个换行符都会导致验签失败。排查时最快的办法是把前端签名函数里打印出的值和你自己算出来的值放在一起逐字符比对。5. 重放之后的状态与上下文问题改了参数却失败的真正原因5.1 为什么请求发出去了服务端却不理你签名通过了、参数也改了但重放还是失败这种时候往往不是算法问题而是服务端有另一套校验机制。我把平时遇到的失败原因整理成了表格现象可能原因解决思路返回“签名过期”时间戳超出允许窗口重放时重新生成当前时间戳并同步重算签名返回“重复请求”nonce/流水号已存在每次重放换一个新 nonce或清空 nonce 字段返回“订单状态错误”订单已支付或已关闭换个新订单或者修改订单状态字段返回“登录失效”token 过期或会话被踢更新 Cookie/Authorization返回成功但数据没变服务端做了幂等处理检查请求里的业务主键换一个新主键直接超时/连接被重置客户端 IP 或设备指纹被风控确认是否在授权范围直接联系接口负责人这张表我是在实际项目里一点点积累出来的。刚开始做重放的时候我总以为是签名没算对折腾半天发现是订单状态变了——第一次重放已经把订单处理了第二次再拿同一个订单号重放服务端当然不理会。5.2 服务端防重放的常见机制要理解为什么重放会失败得先知道服务端到底怎么看待重复请求。服务端防重放通常有这几层时间戳窗口请求里的timestamp与服务器当前时间相差超过一定范围比如 5 分钟就直接拒绝。这是最简单也最常见的防重放手段。nonce 一次性随机数客户端每次请求生成一个唯一 nonce服务端在内存或缓存里记录已经用过的 nonce重复出现就拒绝。没随机数的接口重复请求基本等于合法请求。幂等键服务端对同一个业务主键订单号、流水号只处理一次。第一次请求成功后后续相同的请求返回第一次的结果但不会重复执行业务逻辑。Token 单次有效登录后拿到的 token 只能用一次重放时如果复用了旧 token就会被踢出。理解这些机制后重放失败就不再是玄学了。对策也很直接让每次重放的请求在服务端眼里看起来“像一次新请求”——换时间戳、换 nonce、保证业务主键唯一。但注意这不是让你伪造身份而是在授权测试范围内模拟不同请求状态。5.3 重放时如何保证请求上下文有效另一个容易忽略的问题是请求上下文。真实的 HTTP 请求不是孤立存在的它带着会话状态、来源信息、甚至设备指纹。重放时这些上下文不完整服务端就会怀疑你。我在重放时一般保持“三不动”原则不动 Cookie 和 Authorization它们是会话凭证一旦缺失或过期请求直接失效。如果会话过期就重新登录再抓包。不动依赖性的请求头Origin、Referer、User-Agent 这些头虽然很多后端不校验但一旦校验了改掉就是自己给自己挖坑。保留原值是成本最低的选择。不动业务上下文关联字段比如订单号关联了用户 ID你把用户 ID 改了但订单号没改服务端会发现订单不属于该用户拒绝处理。有一次我重放一个退款接口签名算对了、参数也改了但是返回一直提示“订单不属于当前用户”。排查半天发现我只改了请求体里的用户 ID没改 Cookie 里携带的会话用户信息。服务端是拿会话里的用户去查订单的请求体里的字段反而是冗余的。这个案例很有代表性——签名和防重放只是最外层的关卡业务逻辑校验才是真正决定成败的关卡。6. 实操中容易踩的坑和排查思路6.1 抓包工具本身先被客户端识破很多 App 和网站会检测代理环境一旦发现请求走了代理就拒绝服务或者返回假数据。最常见的是 App 的 HTTPS 证书校验也就是常说的 SSL Pinning。客户端把服务端证书固定死在本地代理工具无法用自己签发的证书解密流量抓包拿到的是密文或者直接断连。对策要看使用的系统是不是你授权的测试环境。如果是自己的调试 App可以在代码里把证书校验关掉如果做的是第三方 App 的授权安全测试需要配合 Hook 手段绕过证书锁定。不管哪种方式都要确保操作在授权范围内这是大前提。Web 端相对好处理直接用浏览器开发者工具F12的 Network 面板就能看到完整请求F12 里看不到数据的情况多半是浏览器版本问题或者站点启用了 CSP 策略需要清除缓存或换个无痕窗口再试。6.2 请求体编码不一致重放出来全是乱码改参数重放最容易被忽略的坑是编码。同样的参数在原始请求里是 URL 编码过的你在重放工具里直接写了原始中文服务端可能就解析不到。举个例子原请求体可能是name%E5%BC%A0%E4%B8%89这是“张三”的 URL 编码。如果你在重放时直接写name张三Content-Type 没变的话服务端按 URL 编码去解析中文就变成乱码。解决方案是保持与原请求一致的编码方式要么原样复制、要么在脚本里用urllib.parse.quote()做编码。JSON 格式的请求体也有类似问题。JSON 里的中文不需要 URL 编码但特殊字符需要转义。如果你把 JSON 里的\n换行符直接写成了真实换行整个 JSON 结构就坏了服务端解析报错。6.3 参数藏在 JS 加密或混淆代码里最简单的情况是明文参数直接拼在请求体里稍微复杂一点的情况是前端先把参数加密请求体里看到的是一串 Base64 或乱码。这种情况下你改明文参数没有意义因为服务端收到的是密文解密出来的结果还是原来的值。处理思路有两条。一条是顺着前端代码的调用栈找到加密函数把加密逻辑复现出来自己把参数加密后重放。另一条是直接操作页面通过开发者工具修改前端变量再触发真实请求——这样发出去的请求就是客户端自己加密生成的你再抓包拿到它的完整内容重放就行。我自己的经验是与其逆向加密算法不如用无头浏览器比如 Puppeteer 或 Playwright自动化操作页面。页面里填入异常参数、触发操作、从浏览器网络请求里拿到加密后的内容再决定是否需要重放。这样做的好处是加密、签名、防重放这些机制全都不用管客户端自己会帮你处理好。写在最后一些实战层面的体会抓包改参数重放这事做久了你会发现真正的难点从来不是工具操作而是理清一条链路上的所有校验逻辑。前端校验是第一层后端参数校验是第二层签名是第三层防重放机制是第四层业务状态校验是第五层。每一层都可能让你的重放请求失败也都有可能被你绕过。而一个接口的安全水平恰恰取决于这五层里最弱的那一层。我个人最大的体会是签名解决的是“参数被篡改”的问题防重放解决的是“请求被复制”的问题这两者经常被混为一谈但实际上是两个独立维度。与其硬记各种绕过技巧不如多花时间理解服务端视角的校验机制。思路通了工具只是顺手的事。如果你刚开始接触这块我的建议很简单先拿自己公司有权限的后台管理接口练手选一个带签名但逻辑不复杂的接口从抓包、定位签名函数、Python 复现签名到重放成功完整走一遍。这条路走通一次之后你再遇到签名接口就不会发怵了。下一次碰到“改了参数为什么还是失败”你就能快速定位到是签名没对齐、时间戳过期还是业务状态不匹配了。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价