
在移动互联网高速发展的今天,APP 已成为我们日常生活中不可或缺的一部分,随着业务逻辑的日益复杂,安全问题也日益凸显。“重放攻击”是一种隐蔽且极具破坏力的攻击手段,它悄无声息地威胁着用户的资金安全与隐私数据。
作为开发者,如何有效地在 APP 开发中防止重放攻击,是构建可信应用架构的必修课。
什么是重放攻击?
重放攻击是指攻击者截获并记录了合法用户的网络请求(如登录请求、支付请求),然后在稍后的时间点,将这些数据包重新发送给服务器,对于服务器而言,由于时间已过,请求看似是刚刚发出的,因此会误以为这是合法用户的新操作,从而导致数据被重复执行。
常见的攻击场景包括:
- 支付漏洞: 攻击者截获支付成功的请求数据包,稍后再次发送,导致用户被重复扣款。
- 登录绕过: 在用户未登录的情况下,直接发送登录请求包,从而绕过身份验证。
- 业务逻辑漏洞: 在投票、签到或抢购活动中,通过重复发送请求获取不当利益。
防止重放攻击的核心原理
要防止重放攻击,核心在于“确保请求的唯一性”和“请求的时效性”,服务器必须能够识别出这个请求是“刚刚发出的”,而不是“以前发出的”。
如果服务器无法区分新旧请求,那么任何加密手段(如 SSL/TLS)都无法从根本上解决问题,因为攻击者截获的加密数据包依然可以完美解密并重放。
常见的防御技术方案
在 APP 开发中,通常采用以下几种技术手段组合来构建防御体系:
时间戳机制
这是最简单直接的防御方式,客户端在发送请求时携带当前的时间戳,服务器接收到请求后,会计算当前时间与请求时间的时间差。
- 实现逻辑: 如果时间差超过了设定的阈值(5 分钟),服务器则判定该请求为过期,拒绝处理。
- 优缺点: 实现简单,但容易受用户设备时间偏差影响,且无法完全防止短时间内的重放。
随机数
为了防止攻击者截获数据包后立即重放,可以使用随机数。
- 实现逻辑: 服务器在生成业务请求(如订单号、Token)时,会生成一个随机数,并将该随机数下发给客户端,客户端在后续请求中必须携带这个随机数,服务器维护一个“已使用随机数”的列表(或使用 Redis 的 Set 数据结构),每次收到请求先检查该随机数是否已存在,如果存在,则判定为重放攻击。
- 优缺点: 有效防止重放,但需要服务器端维护状态,增加了存储压力。
令牌机制
令牌机制通常结合时间戳和随机数使用,是 OAuth 2.0 等认证协议的核心。
- 实现逻辑: 客户端登录成功后,服务器签发一个带有过期时间的 Token,该 Token 包含了用户的身份信息和时间戳,每次 API 请求,客户端都需要携带 Token,服务器验证 Token 的签名是否正确,以及 Token 是否在有效期内且未被重复使用。
- 最佳实践: 对于敏感操作(如支付),建议采用“一次性 Token”策略,即 Token 使用一次后立即失效。
加密与签名
虽然加密不能直接防止重放,但它是防止数据篡改的基础。
- 实现逻辑: 使用 HMAC-SHA256 等算法对请求参数进行签名,如果攻击者截获了数据包并重放,虽然时间戳可能通过,但一旦攻击者修改了数据包中的参数,签名就会失效。“时间戳 + 随机数 + 签名” 是防止重放攻击的黄金组合。
架构层面的防御建议
除了在代码层面实现逻辑判断,在架构设计上也要注意以下几点:
- 服务端校验是核心: 千万不要依赖客户端来验证防重放逻辑(例如让客户端判断时间戳),攻击者可以通过修改 APK 或使用抓包工具轻松