开放问答
分布式网关防重放:nonce 去重放 Redis 还是本地,跨实例一致性怎么保?
该问题的正文、回答与评论。
提问者 温寒山-179 · 状态 open
安全加固防重放nonceRedis分布式一致性
【背景】
我在做一套对外 API 的安全加固,网关是 4 个副本(Go + 自研,跑在 3 节点 K8s 1.28,无云)。鉴权用「签名 + 时间戳 + nonce」三件套:客户端带 ts、nonce、sign=HMAC(secret, method|path|body|ts|nonce),网关验签后要求 |now-ts| ≤ 5min 且 nonce 未出现过,用来挡重放。
【现象 / 卡点】
- 现在 nonce 去重用「每实例内存 map + 定时清理」,4 个副本各存各的,同一个 nonce 打到不同副本就会重放成功——这是个真漏洞,但内存方案扛不住重启丢状态,也不想全量迁 Redis;
- 想换 Redis 做集中去重,但担心:高并发下单个 nonce 的「判重 + 写入」必须原子,否则两个并发请求同时判「不存在」都会放行;
- 时间戳窗口 5min 到底合不合理?窗口越大,nonce 集合越大,Redis 内存压力越大,但窗口太小又会在客户端时钟漂移(NTP 不同步、跨时区)时误杀合法请求。
【已尝试 / 排查】
- 试过
SET nonce:xxx 1 NX EX 300:原子判重 + 自动过期,单条 OK,但压测下 8k QPS 时网关到 Redis 的 RT 从 0.8ms 涨到 4ms,P99 抖动明显,且 Redis 挂了网关直接拒绝所有请求(可用性风险); - 试过把窗口缩到 60s 配合客户端强制 NTP,但有几个客户端是内网老设备,时钟漂 2-3min,误杀率反而升高;
- 没解决:跨实例一致性 + Redis 单点可用性 + 窗口大小三者怎么一起权衡。
【期望得到的答案形态】 希望得到可落地的取舍,而不是「用 Redis 就行」:
- nonce 判重 + 写入的原子方案:Redis(Lua / SET NX EX)vs 本地布隆过滤器 + 短 TTL vs 混合(本地先挡 + Redis 兜底),各自的误判 / 漏判边界;
- Redis 作为去重单点时的降级策略:Redis 不可用时是「全部拒绝」还是「放行但收紧窗口 / 限流」?给出你们的实际选择与理由;
- 时间戳窗口的取值依据:时钟漂移容忍度怎么量化,NTP 没同步的客户端怎么处理,窗口与 nonce 内存/存储规模的关系;
- 压测数据:8k 量级下 Redis 判重的 RT / 抖动,你们集群规模与 Redis 部署形态(单机 / Sentinel / Cluster)。 有实际防重放落地经验的同学,欢迎带你们的 QPS、窗口值和踩过的坑。
评论
暂无评论。