签名验证必须在请求体被任何逻辑消费前完成,否则$request->getcontent()返回空导致验签失败;需在中间件handle()开头调用$request->instance()->getcontent(false)安全读取原始流,并按字典序拼接参数、使用hash_hmac('sha256', $data, $secret_key)计算签名,同时校验秒级timestamp与redis缓存的nonce防重放。

签名验证不是加个中间件就完事——它必须在请求体被任何逻辑消费前完成,否则 $request->getContent() 会返回空字符串,验签必然失败。
中间件里怎么安全读取原始请求体
很多人在中间件里直接用 $request->all() 或 $request->json() 拼签名,结果 JSON 请求永远验不过。根本原因是 Laravel 的解析器会把原生流(php://input)一次性读走,再调就为空。
- 必须在中间件
handle()开头立刻调用$request->instance()->getContent(false)——false表示不重置流指针,后续控制器还能正常读 - 如果是 JSON 请求,别用
$request->json()->all();先json_decode($content, true),再做字段排序和拼接 - Form-data 和 x-www-form-urlencoded 请求,
$request->all()可用,但要注意:它已自动解码 URL 编码,而客户端可能未 decode 就参与签名,两边结构不一致就会失败 - 空 body 时,
$content是空字符串,按约定应统一算作md5('')(即d41d8cd98f00b204e9800998ecf8427e),不能留空或跳过
签名原文拼接为什么总对不上
“明明算法一样,签名就是不匹配”——90% 出在参数标准化不一致。PHP 数组遍历顺序、空格、URL 编码方式、键名大小写,全会影响最终哈希值。
- 所有参与签名的参数(除
signature、_token、timestamp、nonce等非业务字段)必须严格按 key 字典序升序排列,用ksort($params, SORT_STRING) - 每个 value 必须用
rawurlencode(),不是urlencode()—— 前者把空格转成%20,后者转成+,客户端 JS 默认用前者 - GET 和 POST 参数要合并处理:query string 解析后与 body 参数一起排序,不能分开拼
- URI 必须是
$request->getBaseUrl() . $request->getPathInfo()(不含 query),不能用$request->fullUrl()或$request->url()
hash_hmac 为什么不能换 md5 或 Hash::make
用错哈希函数是验签失败最隐蔽的原因之一。它不会报错,只是永远算不出相同结果。
- 绝对不要用
Hash::make():它是为密码设计的慢哈希,带盐、不可逆、每次结果不同,完全不适合签名场景 - 避免用
md5($data . $secret):无密钥保护、易受长度扩展攻击,中间人可截获并篡改请求体后伪造新签名 - 必须用
hash_hmac('sha256', $data, $secret_key):Laravel 内部大量使用(如Str::signed()),确定性强、性能高、抗攻击 -
$secret_key必须从环境变量读取(如config('app.api_secret')),禁止硬编码在中间件或配置文件中
timestamp 和 nonce 防重放的关键细节
签名只防篡改,不防重放。攻击者截一次合法请求,延时重发,签名依然有效——除非你把 timestamp 和 nonce 用对。
-
timestamp必须是秒级整数(time()),不是毫秒;服务端校验误差范围建议 ±300 秒,超限直接返回 401 -
nonce推荐用bin2hex(random_bytes(16))(32 字符随机串),不能是时间戳、自增 ID 或短字符串(易碰撞) - nonce 必须存 Redis,TTL 设为略大于时间窗口(如 600 秒),写入前用
SETNX判断是否已存在;MySQL 写入延迟高,压测时容易击穿 - 这两个字段必须放在请求头(如
X-Signature-Timestamp/X-Signature-Nonce),绝不能塞进 query 或 body —— 否则签名原文和实际传输内容不一致
真正难的不是写对一行 hash_hmac(),而是确保客户端和服务端对「哪段字节参与计算」有完全一致的理解——包括空格、换行、编码、顺序、排除字段。哪怕一个 trim() 漏掉,整个链路就断了。
大量免费API接口:立即使用
涵盖生活服务API、金融科技API、企业工商API、等相关的API接口服务。免费API接口可安全、合规地连接上下游,为数据API应用能力赋能!











