入口层用redis固定窗口限流+微信签名三要素校验(timestamp、nonce、sign)+按openid而非ip限流+幂等key控制+nginx limit_req兜底,可有效防小程序盗刷。

必须校验微信签名,不能依赖 Referer
小程序的 wx.request 不带 Referer,$_SERVER['HTTP_REFERER'] 恒为空,靠它拦截等于没设防。
真正可信的是微信签名三要素:timestamp、nonce、sign:
- 前端用
md5(timestamp + nonce + secret)生成 sign,传入请求头或参数 - 后端先检查
timestamp是否在 ±5 分钟内(防重放) - 再用相同密钥和拼接顺序重算 sign,严格比对(注意大小写和空格)
- 校验失败统一返回 401 Unauthorized,不进业务逻辑
按 openid 限流,不是按 IP
小程序用户身份是 openid,不是公网 IP。同一 WiFi 下多个用户共用一个 IP,按 IP 限流会大面积误伤。
推荐用 Redis 原子操作实现每分钟 QPS 控制:
- 键名格式:
rate_limit:{$openid}:submit_order - 先
$redis->incr($key),再$redis->expire($key, 60) - 立即
$redis->get($key)判断是否超限(如 >30) - 务必用
expire()而非setex(),避免 INCR 创建 key 后过期失效 -
phpredis 扩展建议 ≥ 5.3.0,老版本
expire()对不存在 key 返回 false,易漏判
关键写接口必须加幂等 key
频率限制挡不住脚本反复提交——比如抽奖、下单、发券。光限流不够,得靠业务层幂等。
要求小程序每次请求带上 idempotency_key(如 UUID v4),服务端用它做 Redis 键:
- 收到请求先
SETNX idempotency_key:xxx processing 300(5 分钟过期) - 若设置成功,执行业务并最终写入
idempotency_key:xxx:result - 若设置失败,直接查 result 键返回结果,或查 DB 确认是否已成功
- 不能只依赖数据库唯一索引,因网络超时后客户端可能重试,DB 插入可能已成功但响应未达
Nginx 层加 limit_req 兜底
PHP 层限流失效时(如 FPM 崩溃、代码绕过、Redis 连接失败),Nginx 是最后一道防线。
在 server 或 location 块中配置:
limit_req_zone $binary_remote_addr zone=perip:10m rate=10r/s;limit_req zone=perip burst=20 nodelay;- 对敏感接口单独配更严策略,例如按
$http_authorization或自定义 header 区分
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











