拓冰建站拓冰建站
首页 / 资讯中心 / 正文

请求重放与签名接口:抓包改参的完整实战指南

抓包改参重发这件事做接口开发、测试和安全方向的朋友应该都干过。前期联调最频繁后端接口刚出来你拿着参数对着文档一遍遍手动试每次都要重新拼请求、填Headers、检查签名是不是又变了。等到上了签名机制再想直接改参数重发十有八九被拦在签名校验这一关。这篇文章就围绕着“请求重放”和“签名接口”这两个关键词展开把我实际踩过的坑、用过的工具、跑通过的脚本都摊开说清楚帮你把这条链路打通。1. 请求重放到底在解决什么问题先聊聊请求重放最常见的应用场景。不要一听到“重放”就想到攻击实际上开发调试、接口回归、压测、安全自测每一步都离不开它。比如我最近在调一个创建订单的接口下单传的商品数量是1我想看看传2、传0、传负数会有什么表现最自然的做法就是把抓到的请求保存下来改掉参数再重发一次。这个过程本质上就是请求重放。签名接口则是在这个基础上多了一层门槛。服务端收到请求后会按照约定好的算法重新算出一个签名值和你传上来的签名做比较不一致就直接拒绝。这就意味着你改了参数签名也要同步改否则会在校验环节被拦死。所以做这类接口的调试核心能力就是两件事第一能抓包、能改包、能重放第二能理解签名算法是怎么算出来的并且在重放时把签名也更新掉。你可能会问我不抓包直接在Postman里填参数行不行行但前提是你得知道所有参数的格式和规则一旦接口嵌套了登录态、时间戳、随机数、业务参数签名手动在Postman里复制粘贴就非常容易出错。而抓包改参重放是把你真实浏览器或客户端发出的那份完整请求原封不动拿来改上下文、Cookie、Header都是现成的省去大量手工组装时间也更贴近线上真实的调用方式。1.1 应用场景盘点从接口联调到安全自测请求重放的典型场景我整理了一下基本覆盖了日常和专项工作的几个方向接口联调阶段后端接口刚开发完参数边界、异常情况、权限校验都需要快速验证。不需要等前端页面开发完成直接用抓包工具对接口发起请求效率会高很多。历史问题回归线上出现一个偶发问题抓到了当时的请求参数但在测试环境想复现时页面已经变了、入口找不到了。这时拿着抓包记录里的完整请求直接重放是最快的复现方式。安全自测和渗透测试这是请求重放被聊得最多的地方。验证越权、验证参数校验、验证签名机制是否可靠都需要反复修改参数重发请求观察服务端响应。签名接口在这一步尤其重要如果签名只覆盖了部分字段、或者算法有缺陷很容易通过重放和篡改发现问题。压测与稳定性验证将抓到的真实请求保存下来改成压测脚本的输入样本比凭空构造参数更贴近真实流量。我自己用得最多的是联调和安全自测。联调时能快速判断是前端参数传错了还是后端逻辑有BUG安全自测时能快速判断哪些参数服务端真的校验了哪些形同虚设。1.2 请求重放的两个核心链路抓包与改包请求重放看着简单真正操作的时候会拆成两条链路。一条是抓包链路你要能拿到完整的HTTP请求请求行、Header、Body、Cookie一个都不能少。另一条是改包重放链路你要能修改任意位置的参数并且把请求重新发出去观察服务端返回。抓包工具本身不复杂但细节决定成败。比如HTTP和HTTPS的差别、代理设置、证书安装、移动端抓包这些任何一个环节出了问题抓到的可能都是空包或者CONNECT请求。改包重放更考验功力因为你不仅要改参数本身还要同时处理依赖这个参数的所有上下文。最典型的就是签名你改了请求体里的商品数量那么计算签名时用的原文也会变签名也必须跟着变。此外还有Content-Length请求体长度变了这个字段不更新很多服务端解析会直接异常。还有一类容易被忽略的依赖是Token和时间戳。有的接口把Token放在Header里这个Token有时是登录时签发的和当前请求体无关那改参不影响但也有接口会把请求体内容参与Token的生成这种情况下你改完请求体Token也必须重新生成。时间戳同理很多签名机制会带时间戳字段用来约束请求有效期重放的请求如果间隔太久会被判定为过期。2. 签名接口的原理与常见实现签名机制听起来高大上说白了就是服务端和客户端约定了一套“暗号”用来确认请求数据确实来自可信调用方并且在传输过程中没有被篡改。常见的做法是把请求参数、密钥、时间戳、随机数等按规则拼接成一个字符串然后用哈希算法或对称加密算法算出一个固定长度的签名值和服务端计算出来的结果比对。我接触过的签名实现绝大多数都离不开这三个要素参与签名的参数集合、参数拼接规则、摘要算法。参数集合决定了哪些内容被保护拼接规则决定了原文长什么样摘要算法决定了怎么把这串原文变成签名值。任何一个环节不一致签名校验都会失败。2.1 签名机制在防什么参数篡改与重放很多刚接触签名的同学会问接口都走HTTPS了为什么还要签名这里要分开看。HTTPS解决的是传输过程加密防止数据在网络上被第三方窃听和篡改。但服务端无法确定请求是不是你写的客户端发出来的也没法确定参数在上送到客户端内存时有没有被改过。比如我抓到一个下单请求把价格从100改成1再原样发出去如果服务端只校验HTTPS而不校验签名那这个请求就可能被接受。签名机制的核心作用就是防止参数篡改。它把关键参数纳入签名计算范围改动任何一个字符服务端算出来的签名就对不上。除此之外签名机制还能在一定程度上降低请求重放的风险因为签名里通常会带时间戳和随机数请求发出后超过一定时间就会被判定为无效同一个随机数也只能用一次。但是要注意签名机制并不能完全杜绝重放。如果攻击者抓到一个合法请求在签名有效期内原封不动地转发服务端是没法区分这是正常请求还是恶意重放的。所以现在很多对安全要求高的接口会在签名之外再加一层nonce随机数去重或幂等性控制来解决短时间内的重放问题。2.2 一个典型的签名生成流程拆解我以最常遇到的App接口签名方式为例讲一下通用流程。不同公司算法不一样但思路基本是下面这几步。第一步筛选参与签名的参数。把所有业务参数取出排除掉sign本身、sign_type这类签名相关字段剩下的参数全部纳入签名范围。也有的接口会把固定密钥拼进原文里确保只有持有密钥的客户端才能生成合法签名。第二步按参数名字典序排序。这一步是为了保证无论客户端还是服务端计算拼接顺序都是一致的。字典序就是按照ASCII码从小到大排比如a排在最前z排在最后。排序后把参数拼接成类似key1value1key2value2这样的字符串。第三步在拼接好的字符串末尾或开头加上密钥。常见做法是拼上secretKey或者salt然后整体做MD5、SHA1或者HMAC-SHA256运算。摘要算法得到的结果一般会转成十六进制字符串有的还会要求大写或小写。import hashlib import time import random import string def generate_sign(params: dict, secret_key: str) - str: # 1. 过滤空值和签名相关字段 filtered {k: v for k, v in params.items() if v ! and k not in (sign, sign_type)} # 2. 按 key 字典序排序 sorted_keys sorted(filtered.keys()) # 3. 拼接成 keyvalue 形式 raw_string .join(f{k}{filtered[k]} for k in sorted_keys) # 4. 拼接密钥 raw_string_with_secret f{raw_string}key{secret_key} # 5. 做 MD5 摘要 sign hashlib.md5(raw_string_with_secret.encode(utf-8)).hexdigest().upper() return sign这里有个容易被忽略的点密钥的拼接位置和方式。有的是在最后加keyxxx有的是直接在字符串末尾接上密钥还有的是在字符串开头加。这些细节必须看接口文档或者反编译客户端才能确定没有统一的约定。我在实际调试时吃过不少这样的亏后面会专门讲。3. 抓包改参重放的完整实操说完了思路进入实操环节。这次我以抓包工具Burp Suite为例讲一下从抓包到改参重放的完整过程再介绍带签名接口的自动化重放怎么做。Charles和Fiddler操作思路也类似只是界面和快捷键不同。提前说一句抓包调试请在授权范围内进行最好是用测试环境、测试账号不要拿线上的真实业务数据乱试。3.1 抓包工具的选型与抓包前置准备市面上主流的抓包工具我基本都用过简单对比一下工具平台核心优势适合场景Burp SuiteWindows / macOS / Linux拦截改包能力强Repeater功能强大社区版免费安全测试、深度调试CharlesWindows / macOS界面友好代理设置方便支持断点修改Web和移动端联调FiddlerWindows轻量脚本扩展方便自带Composer重放快速抓包、Windows环境mitmproxyWindows / macOS / Linux命令行交互支持Python脚本控制自动化抓包、二次开发Postman / Apifox跨平台适合手动构造请求和保存请求集合接口文档化管理、简单重放我最常用的是Burp Suite尤其是它的Repeater功能。抓到的请求右键发送到Repeater可以反复修改、反复重放还能看到多轮请求的历史记录。这个功能在调试签名接口时特别有用。抓包前置准备有几件事容易踩坑。Burp默认监听127.0.0.1:8080所以浏览器要先配置代理指向这里。HTTPS请求需要先下载并信任Burp的CA证书否则抓到的都是加密乱码。移动端抓包需要手机和电脑在同一局域网手机WiFi代理指向电脑IP和8080端口同时也要安装证书。iOS新版本对证书信任有额外的开关安装证书后还要在“设置-通用-关于本机-证书信任设置”里开启完全信任安卓7.0以上默认不信任用户证书那就需要测试App开启usesCleartextTraffic或者把证书装进系统证书目录。3.2 用Burp Suite Repeater完成改参重放我拿一个真实的调试过程来演示。假设我现在要调试一个查询订单详情的接口浏览器里已经正常操作过Burp的HTTP History里能看到这个请求。第一步点击请求记录右键选择Send to Repeater或者按快捷键CtrlR。Repeater会打开一个新标签页里面完整还原了原始请求包括请求方法、URL、Header、Body。POST /api/order/detail HTTP/1.1 Host: api.example.com Content-Type: application/json Authorization: Bearer eyJhbGciOi... User-Agent: Mozilla/5.0 Content-Length: 46 {order_id:10086,user_id:9527,ts:1710000000,sign:3F2C6A9B...}第二步我在Body里把order_id从10086改成10087点击Repeater上方的Send按钮请求就会被发出去。此时如果服务端没有签名校验响应会直接返回10087对应的订单数据如果有签名校验大概率会返回签名错误。第三步遇到签名校验失败时我需要同步更新sign字段。最原始的办法是写个脚本算好sign值再手动粘贴到请求里。但这样效率太低改动一次参数就要算一次。更专业的做法是安装Burp的扩展比如自定义Python扩展在每次发送请求前自动重新计算签名。也可以用中间人代理脚本用mitmproxy配合Python脚本做自动改包和签名重算。这里顺带强调一个bug改完Body后Header里的Content-Length必须手动更新。Burp的Repeater在发送时如果请求体发生了变化有时候不会自动更新Content-Length服务端按照旧的Content-Length读取body数据就会截断或者解析失败。我的习惯是改完参数之后顺手看一眼Content-Length和实际body长度是否一致不一致就手动改。3.3 带签名接口的自动化重放脚本Burp的Repeater交互方式适合手动反复调试但如果需要连续重放多个参数组合人肉操作就太慢了。这时候我通常会写一个Python脚本把请求和签名计算逻辑一起封装起来循环去跑。以最常见的JSON接口为例签名计算方式为参数按key字典序排序后拼接为keyvaluekeyvalue末尾加keysecret再取MD5大写。下面的脚本做了三件事构造请求参数、计算签名、发送请求并打印响应。import hashlib import json import requests SECRET_KEY your_secret_key def calc_sign(params: dict) - str: filtered {k: v for k, v in params.items() if k ! sign} sorted_keys sorted(filtered.keys()) raw .join(f{k}{filtered[k]} for k in sorted_keys) raw_with_key raw key SECRET_KEY sign hashlib.md5(raw_with_key.encode(utf-8)).hexdigest().upper() return sign def replay_order_detail(order_id: str, user_id: str): params { order_id: order_id, user_id: user_id, ts: 1710000000, sign: } params[sign] calc_sign(params) resp requests.post( http://api.example.com/api/order/detail, jsonparams, headers{Authorization: Bearer your_token_here} ) print(forder_id{order_id}, status{resp.status_code}, resp{resp.text}) return resp.json() if __name__ __main__: for oid in [10086, 10087, 10088, 0, -1, abc]: replay_order_detail(oid, 9527)这里有一个容易踩的坑params里如果包含了sign字段再参与签名计算算出来的值永远都不对因为sign值会影响它自己。所以calc_sign里第一件事就是把sign字段过滤掉。另外有些接口的签名原文并不是简单的keyvalue拼接而是把整个请求体JSON字符串直接参与签名或者是把参数嵌套结构先拍平再拼接。写脚本前一定要先把签名规则搞清楚最直接的办法是找到开发同事确认或者从客户端代码里逆向出签名函数。如果是线上环境重放脚本还需要注意请求频率。我一般会在每次请求之间加一个随机sleep避免触发风控限流也避免给服务端造成压力。4. 实战中遇到的坑与排查技巧这块内容是我最想写给后来人的因为我在这块交过不少学费。请求重放看起来简单真正做起来各种细节问题能把人磨到怀疑人生。4.1 Content-Length不一致导致请求被服务端拒绝这个坑第一次遇到的时候我花了一个小时才定位到原因。当时我用Burp修改了一个登录接口的请求体把用户名从a改成一个更长的测试值点击发送后服务端一直返回400 Bad Request但去掉body只发GET请求又一切正常。后来我检查请求报文发现Body长度已经从原来的30多变成了50多但Header里的Content-Length还是30多。服务端在读Body时是按照Content-Length指定的长度去读的。长度不对就会读到半个字符或者少读内容JSON解析自然失败。解决办法就是在修改Body后同步把Content-Length更新成正确的长度。Burp的Repeater在有些版本里会自动帮你改但不要依赖这个行为手动确认最稳妥。4.2 签名值为什么总是校验失败签名校验失败是重放签名接口时最常见的问题。我梳理了几个高频原因按出现概率从高到低排一下参与签名的参数范围不一致。客户端可能把sign本身排除在签名计算之外但其他的业务字段、公共字段、甚至Header里的某些字段都参与了签名。你只更新了业务参数但Header里参与签名的字段漏掉了。参数值格式不一致。比如时间戳有人用的是秒级有人用毫秒级比如金额有人的是字符串10.00有人的是数字10参与签名计算时结果完全不同。拼接顺序或者分隔符不对。有的接口不是按照字典序而是按照文档规定的固定顺序有的连接符是有的直接拼成key1value1key2value2。密钥拼接位置不对。我之前遇到一个接口密钥不是加在末尾而是加在字符串开头网上搜到的通用脚本根本算不对最后是翻了客户端的反编译代码才定位到。编码问题导致签名不一致。中文参数、URL编码参数、特殊字符如果两边的编码方式不统一MD5算出来就完全不同。排查这类问题时我的做法是先抓一个已知成功的请求把客户端实际发出的sign值和服务端按规则算出来的值做对比。如果一致说明规则没问题如果不一致再慢慢调整拼接方式、密钥位置、参数范围直到算出来一致为止。这个过程虽然枯燥但非常有效。4.3 时间戳、nonce与幂等性设计的联动关系签名接口除了防篡改往往还会带时间戳和随机数。时间戳的作用是规定请求的有效期比如ts字段与服务器当前时间相差超过5分钟就拒绝请求能有效防止历史请求被无限期重放。nonce的作用是防止同一请求在短时间内被重复提交服务端会把用过的nonce存起来下次遇到相同nonce直接拒绝。这就引出一个实际调试中经常遇到的问题我在Burp里抓到一个请求仔细改了参数算了签名准备重放时发现服务端返回“请求过期”。原因很简单原始请求里的ts是几分钟前生成的已经超过有效期了。解决办法是把ts更新成当前时间戳然后用新的ts重新计算签名。同理如果接口带nonce并且之前已经重放过一次那么后续重放时需要换一个新的nonce再重新签名。签名、时间戳、nonce这三个机制往往是组合出现的理解它们各自的作用和联动关系才能在设计测试用例时想清楚怎么绕过或验证。比如我只想验证参数校验逻辑那就要确保签名、时间戳、nonce都是有效的如果我想验证签名机制本身是否可靠那就要尝试修改参与签名的字段和不参与签名的字段观察服务端反应。4.4 从重放视角看签名机制的防御设计做安全自测时我见过不少签名机制设计得“看似无懈可击实则漏洞百出”的案例。最典型的几个问题包括只对部分参数进行签名把一些关键字段漏在保护范围外时间戳有效期设置过长允许请求在几分钟甚至几小时内重放nonce没有做持久化去重服务端重启后重复请求又能通过签名算法和密钥硬编码在客户端代码中容易被逆向提取。如果你是在设计签名接口我的建议是所有业务关键字段必须参与签名时间戳有效期控制在5分钟以内nonce至少要在内存中做短时去重密钥不要用对称密钥一把走天下至少在密钥管理上要做分级、定期轮换。如果你是在测试签名接口建议反向思考备份一份有效请求逐个字段尝试修改并重放看看哪些字段变了签名还能通过哪些字段虽然在签名范围内但值没有实际校验。这样一轮做下来接口的安全水平大概什么样心里就有数了。按照我的习惯抓到请求后第一件事是整体浏览一遍Header里有哪些自定义字段Body里有哪些参数哪些参数是参与签名的、哪些只是透传。有条件的接口我会先去翻接口文档确认签名规则没有文档就通过实测来反推。等签名逻辑搞清楚之后再开始正式调参和重放效率会高很多。这个习惯帮我省下了大量反复试错的时间建议你也试试。
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门