
一、背景
项目组曾提出两版方案,计划在 Gateway 网关层或业务微服务层引入”防重放票据(Ticket)+ 签名校验”机制,用于防御:
- 表单快速重复提交
- 请求重放攻击
- 请求参数被中途篡改
本文记录完整的推理过程与最终结论,供后续团队成员参考,避免同一问题被重复讨论。
二、最终结论(先给结论)
框架层(Gateway、common 模块、AOP 拦截器)不新增任何防重放/防篡改/通用幂等机制。
原有票据申请、签名校验、Gateway 全局过滤器等方案全部废弃,不予实现。真正需要”同一操作不能被执行两次”的具体业务接口(如报销提交、请假审批等),由业务方自行实现幂等,不依赖任何框架层拦截器。
三、推理过程
3.1 初始方案的问题
最初的两版方案(网关级 GlobalFilter 拦截 + 业务层 AOP 切面签名校验)存在以下技术缺陷:
| 问题 | 说明 |
|---|---|
| 阻塞调用 | Gateway 基于 WebFlux 响应式模型,方案中直接使用同步 StringRedisTemplate,会阻塞 Netty EventLoop 线程,高并发下吞吐量骤降 |
| 序列化不一致 | 签名基于”申请票据时的原始 JSON”计算,校验时却基于”反序列化再重新序列化”的对象计算,两次序列化结果不保证字节级一致(字段顺序、多余字段丢弃、数值精度漂移等),会导致误判 |
| Header 伪造风险 | userId 从 Header 读取,未说明如何防止外部请求伪造该 Header 绕过 AuthFilter |
| Order 顺序未对齐 | 新增过滤器的执行顺序未与现有 AuthFilter/XssFilter 等对齐 |
| 网关职责越界 | 票据签发、签名校验属于业务/安全逻辑,不应放入只负责路由转发的 Gateway |
3.2 概念澄清:防连点 / 防重放 / 真幂等 / 防篡改是四个不同的问题
| 概念 | 防的是什么 | 结论 |
|---|---|---|
| 防连点 | 用户短时间内重复点击提交按钮 | 属于用户体验问题,非安全问题 |
| 防重放 | 无身份凭证的第三方截获并重发请求包 | 已被 HTTPS/TLS 在协议层完整解决,见 3.3 |
| 真幂等 | 同一业务意图不应被重复执行(如订单创建) | 业务语义问题,需业务层实现(唯一键 + 数据库唯一约束) |
| 防篡改 | 请求内容在传输过程中被中途修改 | 已被 HTTPS/TLS 在协议层完整解决 |
3.3 关键结论:HTTPS/TLS 已经解决了协议层的重放与篡改问题
- TLS 记录层自带序列号 + MAC(或 AEAD tag),同一密文记录在同一连接内重复送达会被直接识别丢弃。
- 会话密钥由 ECDHE 每次握手协商产生,与具体连接绑定,无法跨连接复用。
- 因此,不掌握明文/Token 的纯网络中间人,理论上无法构造出服务器会接受的重放请求。
- 例外情况:若基础设施启用了 TLS 1.3 的 0-RTT(早期数据)恢复模式,规范本身明确指出该模式下的早期数据可能被重放,需要应用层自行处理非幂等操作,或直接关闭 0-RTT。建议检查网关/CDN/负载均衡是否开启该选项,若开启需在基础设施层面关闭或规避,而非在应用层补一套防重放逻辑。
3.4 信任边界的确立
- 用户身份合法性完全由 Token 承载。Token 一旦泄露,攻击者的行为在系统层面与用户本人行为无法区分,等价于用户本人操作。
- 因此:”用户自己(或 Token 持有者)手动重放/篡改请求参数”,不属于协议层攻击,而是业务层是否允许重复提交/是否需要幂等的问题,责任边界在业务代码,不在框架。
- 密钥交换、身份判定等如需业务侧扩展,可直接复用 HTTPS 已建立的信任链(证书链认证服务端 + Token 认证客户端),无需重新构建一套 PKI 体系。
3.5 被否决的补充方案:业务级”意图确认”双密钥签名机制
讨论中曾提出”服务端暂存执行参数、客户端公私钥双向签名确认”的强不可否认(Non-repudiation)方案,用于防止用户后续抵赖。结论:
- 若浏览器端私钥以 JS 层面生成并存储在 localStorage 等位置,其安全等级与 Token 完全相同(均可被 XSS/恶意插件读取),并不能提供额外的不可抵赖性保障。
- 真正具有法律级不可否认意义的方案需要依赖 WebAuthn/Passkey 等硬件级密钥隔离机制,实现成本高。
- 本项目现有业务场景(教务系统类,无电子签章/合同举证类强合规需求)不构成实现该机制的必要性,故不予实现。
3.6 防连点与抢票场景的最终定位
- 防连点(用户误触/网络重传/多标签页导致的意外重复请求):本质是数据完整性问题,交由业务方在具体接口中按需实现幂等(唯一键 + 数据库唯一约束),不做成框架通用拦截器。
- 抢票类场景的”单用户高频请求”:属于限流范畴,由现有限流组件解决,不在本次讨论范围内。
- 抢票类场景的”库存超卖”:属于并发控制问题,由分布式锁/原子扣减(如 Redis
DECR)等业务代码解决,与”防重放”无关,不应混为一谈。
四、最终结论汇总
- 不改动 Gateway,网关继续只承担路由转发、鉴权透传、XSS 过滤、黑名单拦截等原有职责。
- 不新增任何通用的防重放/防篡改/防连点 AOP 或过滤器。
- 不实现票据(Ticket)签发与签名校验机制。
- 真正需要”同一操作不可重复执行”的具体业务接口,由该业务模块自行实现幂等:生成业务唯一键,落库时依赖数据库唯一索引兜底并发,需要时对重复请求返回首次执行结果。
- 若后续基础设施排查发现启用了 TLS 1.3 0-RTT,需评估是否关闭,属于运维/基础设施配置事项,不需要应用层介入。
- 若未来出现电子签章、合同类强合规举证需求,再单独评估引入 WebAuthn 等硬件级签名方案,本次不予实现。
五、备注
本文档用于记录一次完整的方案推翻过程,核心价值在于推理链条本身:从”网关全局过滤器 + 签名票据”的复杂方案,逐步收敛为”框架不做任何改动、问题下沉到业务层”的结论。若后续团队成员再次提出类似的防重放/防篡改框架需求,可基于本文档的推理复核是否存在新的、未被覆盖的场景,而非重复从零推导。
