客户端防重放设计

需求概述

客户端信道早在1.1版本中便实现了服务器防重放攻击功能,但始终没有实现客户端防重放攻击。这样会使得客户端存在被重放攻击的危险,如用户在转账时被重放了转账失败页面,导致用户重复转账。 为此,我们需要在客户端信道中实现客户端防重放功能。

功能需求

我们需要实现以下需求:

  1. 在服务器响应中增加序列号,实现客户端防重放功能
  2. 兼容之前版本的信道通信,以便在升级服务器后,可以兼容旧客户端。

设计

为兼容旧版本信道协议,我们需要新增1.5版本协议来实现客户端防重放功能。1.5信道协议在1.4协议基础上进行升级。

防重放逻辑

  • 在服务器响应报文的前面增加组别和防重放序列号。
  • 格式与请求序列号格式相同,即组别(1位byte) + 序列号(8位byte) + 响应内容。
  • 由于从1.4版本后摘要值添加在响应内容前,因此1.5版本需要将摘要值添加在序列号之前,即摘要 + 组别 + 序列号 + 响应内容。
  • 客户端收到响应后先解析组别和序列号,并与本地同组别的请求序列号进行比较,验证序列号合法性。如果请求序列号与响应序列号相同则视为合法,合法再处理校验摘要值及响应内容,如果非法则提示网络错误。其中网络错误提示信息可配置。
  • 会话超时时,服务器统一返回20位byte(全是0)数据,不分国密非国密。

序列号生成逻辑

  • 响应序列号生成的规则为:与本次客户端请求序列号相同。
  • 由于服务器本地可以获取到当前请求对应的请求序列号,因此响应序列号只需使用该值即可。

响应hamc校验摘要值计算

  • 由于序列号作为响应内容的一部分,因此摘要需要以加入序列号之后的响应内容来计算。即摘要值 = 对(组别 + 序列号 + 响应内容)做hamc加密。
  • 国密加密模式下摘要值为32位byte,非国密模式下摘要值为20位byte。

HTTP防重放逻辑

修改接口ewp_ssl:ssl_sign/2处理逻辑:

  • 修改摘要值的计算方法
  • 响应报文修改为:摘要 + 组别 + 序列号 + 响应内容

TCP防重放逻辑

修改接口ewp_ssl:ssl_sign/2处理逻辑:

  • 修改摘要值的计算方法
  • 响应报文修改为:{tcp, 摘要, 组别 + 序列号, 响应内容}
  • 根据TCP设计文档 4.1.2 TCP接口,服务器响应格式的ResponseMessages,追加Type类型3,表示 组别(1位byte) + 序列号(8位byte),格式为:Type(1 byte) + Length(4 bytes) + Content(Length bytes)。如:<
<think>好的,我现在需要在Spring Boot中实现防重放攻击的机制。首先,我得理解什么是重放攻击。根据引用[3]提到的,重放攻击是攻击者截获合法请求后重复发送,导致重复操作,比如重复扣款。所以,防重放的核心是确保每个请求只能被处理一次,或者在一定时间内有效。 那如何实现呢?时间戳是一个常见的方法。服务端校验请求的时间戳,如果超出允许的时间范围(比如±5分钟),就拒绝请求。这可以防止过期的请求被重复使用。此外,可能还需要结合随机数(Nonce)和签名机制来增强安全性。 接下来,我需要考虑具体步骤。首先,客户端生成时间戳和随机数,然后使用某种算法生成签名,比如HMAC-SHA256,将参数和密钥结合起来。服务端接收到请求后,先检查时间戳是否在有效期内,然后检查随机数是否已经被使用过,最后验证签名是否正确。 在Spring Boot中,可以通过拦截器或者过滤器来实现这些检查。比如,创建一个自定义的过滤器,在请求到达控制器之前进行时间戳、随机数和签名的验证。对于随机数的存储,可以使用缓存,比如Redis,设置过期时间,确保一段时间内的随机数唯一。 另外,引用[2]中提到Spring Security的注销机制,虽然不直接相关,但说明Spring Boot的过滤器机制可以用来处理安全相关的逻辑。可能需要配置Spring Security来整合这些防重放的检查。 还需要考虑密钥的管理,客户端和服务端如何安全地共享密钥。可能每个客户端有一个唯一的密钥,存储在安全的配置中心,服务端根据客户端ID获取对应的密钥进行签名验证。 最后,测试和日志记录也很重要。需要确保在请求被拒绝时记录详细信息,方便排查问题。同时,压力测试确保这些检查不会显著影响性能。</think>在Spring Boot中实现防重放攻击的核心是通过时间戳、随机数(Nonce)和签名验证的组合机制,以下是分步实现方案: --- ### 一、技术实现步骤 #### 1. **客户端请求规范** - **时间戳**:每个请求必须携带当前Unix毫秒时间戳(如`timestamp=1625558400000`) - **随机数(Nonce)**:每次请求生成唯一随机字符串(如UUID) - **签名(Signature)**:使用HMAC-SHA256算法对参数签名,例如: $$ \text{signature} = \text{HMAC-SHA256}(\text{secretKey}, \text{timestamp + nonce + requestBody}) $$ #### 2. **服务端校验逻辑** ```java // 自定义过滤器实现 public class ReplayAttackFilter extends OncePerRequestFilter { @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) { // 1. 校验时间戳有效性(允许±5分钟误差) long currentTime = System.currentTimeMillis(); long requestTime = Long.parseLong(request.getHeader("timestamp")); if (Math.abs(currentTime - requestTime) > 300000) { throw new InvalidRequestException("请求已过期"); } // 2. 校验Nonce唯一性(使用Redis存储已用Nonce) String nonce = request.getHeader("nonce"); if (redisTemplate.hasKey(nonce)) { throw new InvalidRequestException("重复请求"); } redisTemplate.opsForValue().set(nonce, "used", 5, TimeUnit.MINUTES); // 3. 验证签名(从数据库获取客户端密钥) String clientId = request.getHeader("clientId"); String secretKey = clientService.getSecretKey(clientId); String generatedSign = hmacSha256(secretKey, timestamp + nonce + requestBody); if (!generatedSign.equals(request.getHeader("signature"))) { throw new InvalidRequestException("签名无效"); } chain.doFilter(request, response); } } ``` #### 3. **Spring Boot配置** ```java @Configuration public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http.addFilterBefore(new ReplayAttackFilter(), UsernamePasswordAuthenticationFilter.class); } } ``` --- ### 二、最佳实践建议 1. **时间窗口动态调整** 根据业务场景配置时间误差阈值(如支付场景设为3分钟,普通接口5分钟)[^3]。 2. **Nonce存储优化** 使用Redis集群存储已用Nonce,设置自动过期时间(时间窗口+缓冲期),避免内存泄漏。 3. **密钥安全管理** - 每个客户端分配独立密钥,定期轮换 - 密钥存储使用Vault或KMS服务,避免硬编码 4. **流量监控与告警** 对频繁触发防重放规则的IP进行限流,并触发安全告警。 --- ### 三、增强措施 1. **请求序列号(Sequence ID)** 对高敏感操作添加自增序列号,服务端校验序列号的连续性。 2. **HTTPS强制使用** 防止中间人获取明文请求进行重放。 3. **业务层幂等性设计** 如支付接口通过订单ID保证幂等性,即使请求重放也仅生效一次[^3]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值