最稳妥的签名方式是直接使用 hash_hmac(),因其采用标准 hmac 算法、抗长度扩展攻击、默认 sha256 且无需扩展;须注意参数顺序、数据规范化(ksort + http_build_query)、恒定时间验签(hash_equals)、统一 utf-8 编码及避免硬编码密钥。

签名用 hash_hmac() 最稳妥
直接用 hash_hmac(),别手写 MD5 拼接或用 md5($data . $key)。前者是标准 HMAC 算法,抗长度扩展攻击;后者容易被绕过,尤其当 key 在后、data 可控时。PHP 自带的 hash_hmac() 默认用 SHA256,安全且无需额外装扩展。
常见错误:传错参数顺序——hash_hmac() 是 hash_hmac($algo, $data, $key),不是 ($data, $key, $algo)。写反了会返回 false 或空字符串,但不报错,调试时很难发现。
实操建议:
- 固定用
'sha256'算法,兼容性好,强度够用 - 密钥
$secret存在配置文件里,**绝不硬编码在接口逻辑中** - 待签名数据必须是确定顺序的字符串——推荐先
ksort()关联数组,再http_build_query()(注意不加urlencode的原始值要统一处理)
签名前必须规范数据格式
后端验签失败,80% 出在数据没对齐。前端传来的字段顺序、空格、类型(比如 "1" 和 1)、是否含多余键,都会让签名不一致。
正确做法是:约定只对业务参数签名,排除 sign、timestamp 本身(如果 timestamp 用于防重放,它应参与签名)、nonce 等非业务字段。然后强制转换类型、trim 字符串、统一 null 表示(如转成空字符串或删掉该键)。
示例片段:
$params = [
'order_id' => 'ORD123',
'amount' => 99.9,
'user_id' => 'U789',
];
// 排序 + 过滤空值 + 强制字符串化
ksort($params);
$params = array_filter($params, function($v) { return $v !== null && $v !== ''; });
foreach ($params as &$v) {
$v = (string)$v;
}
$data_string = http_build_query($params, '', '&', PHP_QUERY_RFC3986);
$sign = hash_hmac('sha256', $data_string, $secret);
验签时要注意时序和字符编码
验签逻辑跑得再对,也可能被 timing attack 利用。PHP 的 === 字符串比较是松散的、有短路优化的,攻击者可通过响应时间差异爆破签名。必须用 hash_equals($expected, $given) ——它是恒定时间比较,PHP 5.6+ 原生支持。
另一个坑是字符编码:如果前端用 UTF-8 发送中文,而后端 $_POST 或 file_get_contents('php://input') 没统一转码,hash_hmac() 输入字节流就不同。务必确认整个链路用 UTF-8,必要时对输入做 mb_convert_encoding($input, 'UTF-8', 'auto')。
还要检查 HTTP 头:Content-Type: application/x-www-form-urlencoded 和 application/json 的解析方式完全不同。JSON 请求需先 json_decode(file_get_contents('php://input'), true),再走上面的排序+拼接流程。
简单场景下别碰 RSA 或证书签名
只要不是对接银行、政务系统这类强合规要求,纯内部后台通信或小程序后端,hash_hmac() 完全够用。引入 OpenSSL 做 RSA 签名,反而增加密钥管理、填充模式(PKCS#1 v1.5?PSS?)、base64 编解码、公私钥分发等复杂度,还容易因 openssl_sign() 返回 false 却忽略错误而静默失败。
如果真需要非对称,优先考虑用现成 SDK(比如微信支付的 wechatpay-php),而不是自己封装 openssl_* 函数。自己写的 RSA 签名代码,连 PEM 格式换行符多一个都可能验不过。
真正容易被忽略的是密钥轮换机制——上线后没人动 $secret,一用就是两年。应该预留 sign_version 字段,支持新旧密钥并存过渡,否则某天突然改密钥,所有存量请求全挂。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











