签名算法升级必须重写 verifySign 方法,需统一参数排序、URL 编码、拼接规则,并用 hash_hmac('sha256', $data, $key) 校验;严禁混用加密与签名,Key 长度≥32 字节,禁用 md5/sha1。

签名算法升级必须重写 verifySign 方法
ThinkPHP 本身不内置标准请求签名验证逻辑,所谓“支持多种加密方式”是开发者自己封装的。如果你正在用老版本签名(比如只用 md5($params . $key)),直接换 hash_hmac('sha256', $data, $key) 会失败——因为服务端和客户端必须用完全一致的拼接规则、编码格式、参数排序逻辑。
- 旧签名常见错误:没对参数键名排序,导致 GET 请求中
a=1&b=2和b=2&a=1算出不同签名 - 新签名必须统一做:参数按 key 字典序排序 → URL 编码 value → 拼成
k1=v1&k2=v2字符串 → 再进 HMAC - 注意
http_build_query()默认不排序,要用ksort()预处理数组 - 如果接口要兼容旧客户端,得在验证前加个字段判断版本,比如
sign_version=2
ThinkPHP 6 的中间件里怎么安全取原始参数
别直接用 $request->param() 做签名验证——它会自动合并 GET/POST/Route 参数,还可能触发类型转换(比如把 "0" 转成整数 0),导致签名不一致。
- GET 参数用
$request->get(),POST 用$request->post(),分开取再合并 - 务必用
INPUT_RAW方式读取 body,避免框架自动解析 JSON 后丢失原始字符串格式 - 如果用了
json提交,得先file_get_contents('php://input')拿原始字节,再json_decode($raw, true),不能依赖$request->post() - 所有值必须保持原始字符串形态,
(string)$val强转一次,防止布尔值变""或"1"
hash_hmac 和 openssl_encrypt 别混用场景
签名不是加密,hash_hmac 是单向校验,openssl_encrypt 是双向加解密。很多团队升级时误把签名改成 AES 加密,结果客户端验签失败还查不出原因。
- 签名目的只是防篡改,不需要还原原始参数,必须用
hash_hmac('sha256', $data, $key)这类函数 -
openssl_encrypt适合敏感字段(如手机号)传输,但它的输出含 IV、padding、base64 编码,根本没法当签名字段比对 - Key 长度影响安全强度:
hash_hmac的 key 建议 ≥32 字节;若用短 key,SHA256 会被降级为弱哈希 - 别用
md5或sha1做签名核心算法,已被证明可碰撞,NIST 已弃用
测试阶段最容易漏掉的三个边界
上线前不跑全量边界 case,上线后就收报警。签名这种底层逻辑,错一点整个链路就断。
- 空值参数:
user_id=(等号后为空)和user_id=null必须视为不同,且需明确约定哪一种算合法空 - 特殊字符:参数值含
&、=、%、中文、emoji,必须严格按 RFC 3986 URL 编码,不能用urlencode()(它编码空格为+),得用rawurlencode() - 时间戳容错:
timestamp字段通常要求 5 分钟内有效,但服务器和客户端时钟偏差超过阈值时,要返回明确错误码(如4001),而不是让签名失败掩盖真实问题
参数签名不是加个函数调用就完事,关键在两端规则咬合严丝合缝。哪怕一个空格编码不一致,或者排序时忽略大小写,都会让签名永远对不上。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!










