在Web应用中,重放攻击(Replay Attack) 是指攻击者截获用户的有效请求后,重新发送该请求以伪造操作(如重复支付、越权访问等)。以下是防御重放攻击的常用方法及原理分析:
1. Token机制(一次性令牌)
-
原理:
- 服务器生成唯一Token(如UUID),返回给客户端。
- 客户端需在后续请求中携带该Token。
- 服务器验证Token有效性后立即失效(如删除或标记为已使用)。
-
实现:
// 登录后返回Token HTTP/1.1 200 OK Set-Cookie: csrf_token=abc123; HttpOnly; Secure // 请求需携带Token POST /transfer HTTP/1.1 Cookie: csrf_token=abc123
- 适用场景:表单提交、敏感操作(如转账)。
2. 时间戳 + 超时验证
-
原理:
- 客户端在请求中添加当前时间戳(如
timestamp=1679800000
)。 - 服务器检查时间戳是否在合理范围内(如 ±5分钟内)。
- 客户端在请求中添加当前时间戳(如
- 增强方案:结合Token使用,避免攻击者篡改时间戳。
-
代码示例:
// 服务端验证逻辑 long requestTime = request.getParameter("timestamp"); long serverTime = System.currentTimeMillis() / 1000; if (Math.abs(serverTime - requestTime) > 300) { // 5分钟容忍窗口 throw new SecurityException("请求已过期"); }
3. Nonce(一次性随机数)
-
原理:
- 客户端生成唯一随机数(Nonce),随请求发送。
- 服务器记录已使用的Nonce,拒绝重复值。
- 优势:无需服务器生成Token,适合分布式系统。
- 注意:需结合签名(如HMAC)防止Nonce被篡改。
4. 请求签名(如HMAC)
-
原理:
- 客户端使用密钥对请求参数签名(如
sign=HMAC(params + timestamp, key)
)。 - 服务器验证签名有效性及时间戳。
- 客户端使用密钥对请求参数签名(如
- 适用场景:API接口、无状态服务。
-
示例:
# 客户端生成签名 import hmac params = "amount=100×tamp=1679800000" sign = hmac.new(b"secret_key", params.encode(), "sha256").hexdigest() # 服务端验证 expected_sign = hmac.new(b"secret_key", params.encode(), "sha256").hexdigest() if request.sign != expected_sign: return "签名无效"
5. HTTPS + 安全Cookie
-
作用:
- HTTPS加密传输内容,防止请求被截获。
- 设置Cookie的
Secure
、HttpOnly
、SameSite
属性,限制跨站请求。
-
配置示例:
# Nginx配置HTTPS ssl_certificate /path/to/cert.pem; ssl_certificate_key /path/to/key.pem; # Cookie安全属性 Set-Cookie: session_id=xyz; Secure; HttpOnly; SameSite=Strict
6. 幂等性设计
-
原理:
- 对关键操作(如支付)设计幂等接口,即使重复请求结果也一致。
- 通过唯一交易号(
idempotency_key
)去重。
-
实现:
POST /payment HTTP/1.1 Idempotency-Key: req_12345
综合防御策略建议
- 敏感操作:使用Token + 时间戳 + 签名。
- API接口:Nonce + HMAC签名 + HTTPS。
- Web表单:CSRF Token + HTTPS。
- 支付场景:幂等性设计 + 双重验证(如短信验证码)。
注意事项
-
Token存储:避免将Token存储在本地存储(易被XSS攻击获取),优先使用Cookie的
HttpOnly
属性。 - 时钟同步:时间戳方案需考虑客户端与服务端时间偏差(如NTP同步)。
- 密钥管理:签名密钥需安全存储,避免泄露。
通过组合上述方法,可有效防御重放攻击,具体方案需根据业务场景和安全需求权衡。