thinkphp6.x接口签名必须严格遵循「可复现、防篡改、抗重放」三原则,核心是服务端100%还原客户端原始输入;需统一参数来源与拼接规则,禁用$request->param(),按请求类型分别解析原始流并ksort+rawurlencode;强制校验timestamp(±5分钟)和nonce(redis去重);密钥须环境变量注入、分客户端隔离;签名统一用hash_hmac('sha256');验签前置至中间件,失败即返回401且不泄露错误细节。

ThinkPHP6.x 接口签名必须基于「可复现、防篡改、抗重放」三原则设计,核心不是选哪种哈希函数,而是服务端能否100%还原客户端签名时的原始输入。只要参数顺序、编码、过滤逻辑、时间戳来源有一处不一致,验签就会失败。
签名原文构造:严格统一输入源与拼接规则
不能依赖 $request->param(),它会合并 GET/POST 并自动转义,破坏原始字节一致性。应按请求类型分别处理:
- 表单提交(
application/x-www-form-urlencoded):用$request->getInput()读原始流,再parse_str($raw, $data)解析 - JSON 提交(
application/json):同样用$request->getInput(),再json_decode($raw, true) - GET 请求或混合场景:显式合并
array_merge($request->get(), $parsed_body) - 所有参数需
ksort()按键字典序升序排列,排除sign、signature、timestamp、nonce、app_key等非业务字段 - 每个值必须
rawurlencode()(不是urlencode()),空格编码为%20而非+
动态因子校验:时间戳与随机串不可省略
仅靠参数+密钥签名等于裸奔。必须引入两个动态因子并严格校验:
-
timestamp:客户端生成的秒级时间戳,服务端校验
abs($client_ts - time()) (±5 分钟),不校验毫秒,避免服务器时钟偏差误杀 -
nonce:16位以上随机字符串,存 Redis 去重,key 为
"nonce:{$app_id}:{$nonce}",TTL 设为 300 秒;写入即过期,不查旧值 - 二者必须参与签名原文拼接(如
×tamp=1716717120&nonce=abc123...),且在签名前从参数中剔除,防止循环依赖
密钥管理与签名计算:安全与隔离并重
密钥泄露即全线失守,必须规避硬编码和明文存储:
- 密钥(
app_secret)通过环境变量注入,如API_SECRET_IOS=xxx,用Env::get('API_SECRET_IOS')获取 - 不同客户端(iOS、Android、Web)分配独立密钥,通过请求头
X-App-Key或参数app_key查表匹配,避免单点泄露影响全局 - 签名算法统一用
hash_hmac('sha256', $string, $secret),不使用 MD5 或简单拼接 - 若需更高安全性,可升级为 RSA-SHA256:私钥签名,公钥验签;注意 PEM 公钥格式必须为
-----BEGIN PUBLIC KEY-----,且验签前原文构造规则须与签名端完全一致
验签执行位置与错误响应:防线前置、信息收敛
签名验证是请求合法性第一道闸门,必须卡在中间件,绝不能进控制器:
- 注册自定义中间件
ApiSignatureCheck,确保在ValidateRequest之后、控制器执行之前运行 - 验签失败立即终止:
return json(['code'=>401,'msg'=>'Unauthorized'])->send();exit;,不走后续任何逻辑 - 错误响应一律返回 HTTP 401 + 统一 JSON 格式,禁止提示「时间戳超时」「nonce 已存在」「签名不匹配」等细节
- 连续 5 次失败自动对
app_id或 IP 做 Redis 限流,防暴力试探
大量免费API接口:立即使用
涵盖生活服务API、金融科技API、企业工商API、等相关的API接口服务。免费API接口可安全、合规地连接上下游,为数据API应用能力赋能!











