发布于2026-07-11 阅读(0)
扫一扫,手机访问
Middleware),不是因为“更高级”,而是它天然拦截所有请求、不依赖控制器是否继承基类或是否漏写校验。
常见错误现象:app\controller\User::update() 里手动调 checkSign(),结果 app\controller\Pay::notify() 忘了加,攻击者直接伪造回调参数绕过校验。
- 中间件能统一处理 GET、POST、JSON 请求体,避免各处重复解析
- 若用 Controller,必须确保所有入口方法都调用同一套校验逻辑,且不能跳过 __construct() 或前置钩子
- ThinkPHP 5.1 的 filter 参数过滤机制不校验签名,仅做类型转换,别混淆
md5($params . $secret) 是典型错误——它无法防重放、易被长度扩展攻击,且 secret 若拼在末尾,攻击者可构造 param1=a¶m2=b%00...&sign=xxx 绕过(部分框架对 %00 截断)。
正确做法是用 hash_hmac('sha256', $data_string, $secret),其中 $data_string 是按 key 字典序排序后拼接的 key=value 对(不含 sign 字段),并统一用 & 连接。
- 必须剔除 sign 字段再参与签名,否则形成循环依赖
- 时间戳字段(如 timestamp)建议强制要求,且服务端只接受 ±5 分钟内的请求,防重放
- 不要把 nonce 存数据库做去重——高并发下性能差;可用 Redis SETNX + 过期时间,键为 nonce:{value}
input() 拿不到原始数据?input() 默认返回已解析的数组,但签名必须基于原始请求体(尤其是 JSON)。直接对 input('post.') 签名会失败——它已转义、已合并 GET/POST、丢失原始顺序和空格。
正确路径是读原始输入流:file_get_contents('php://input'),再根据 Content-Type 分支处理。注意:该流只能读一次,后续 input() 仍可用,但中间件里别反复读。
- 当 Content-Type: application/json,直接用 file_get_contents('php://input') 得到原始 JSON 字符串
- 当 Content-Type: application/x-www-form-urlencoded 或未设置,用 $_POST + $_GET 合并后按规则排序拼接,但需还原原始编码(如空格是 + 还是 %20)
- ThinkPHP 6 的 Request::raw() 可替代 file_get_contents,更安全,但同样不可重复调用
$_GET 和 $_POST 中的键名大小写敏感:前端传 UserId,PHP 接收却是 userid(尤其 Nginx + FastCGI 配置不当)
- URL 中的 + 被自动转成空格,而签名时没 decode:应统一用 urldecode() 处理所有 value 再拼接
- Windows 开发环境换行符是 \r\n,Linux 是 \n,若签名字符串含多行文本(如 base64 图片),会导致哈希值不同
复杂点在于:签名本身不难,难的是所有环节——前端拼参、传输编码、服务端解析、排序规则、secret 存储方式、时钟同步——必须严丝合缝。少一个环节对不上,整个链路就断掉。
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
正版软件
正版软件
正版软件
正版软件
正版软件
1
2
3
7
8