美团接口被刷十万QPS,怎么防?
《美团接口被刷十万QPS,怎么防?》共 0.4 万字,通篇围绕 监控、安全、日志、权限 展开,归在「后端与系统架构」这一层。
适合给 AI 系统搭底座、要管得住的人
目录骨架(8 节)
- 接口被狂刷的严重后果
- 接口狂刷的主要防护措施:
- 交互式验证
- 安全参数校验
- 使用 HTTPS
- 用户访问认证
- 资源访问授权
- 访问限流
分享内容
- 接口被狂刷的严重后果
- 接口狂刷的主要防护措施(参数校验、资源授权、限流、IP封禁、日志监控等)
接口被狂刷的严重后果
恶意攻击者通常会通过自动化工具进行攻击,尤其是会针对一些高频接口、核心接口进行恶意的访问,恶意的攻击,比如:
- 注册登录接口
- 秒杀抢购接口
- 等等
接口被狂刷会带来很高的瞬时吞吐量,很容易超过 1Wqps,甚至 10WQPS。这样的超高并发,会导致系统的瞬时雪崩,严重的可能会导致线上系统 瘫痪。
接口狂刷的主要防护措施:
- 交互式验证
- 安全参数校验
- 使用 HTTPS
- 用户访问认证
- 资源访问授权
- 访问限流
- IP 封禁
- 日志监控和异步分析
- 升级硬件设备
- 基于时序的统计预警
交互式验证
主要包括:
- 验证码验证:在发送验证码之前,可以要求用户输入一个验证码,以验证用户的身份。这种方式可以有效地防止自动化攻击。
- 人机验证:人机验证是一种更高级的验证方式,可以检测用户行为是否类似于自动化攻击。例如,可以要求用户在发送验证码之前完成一个简单的任务,如拖动滑块或识别图片中的文字。
安全参数校验
当接口被恶意狂刷时,可以通过安全参数校验来防止这种攻击。安全参数校验是指在接口请求中添加一些校验参数,例如时间戳、随机字符串、签名等,来验证请求的合法性。这样可以防止攻击者通过恶意程序进行大量的请求攻击。
具体来说,可以通过以下步骤来实现安全参数校验:
- 在接口请求中添加时间戳参数,例如:timestamp=1622945123。
- 在接口请求中添加随机字符串参数,例如:nonce=abc123。
- 将所有请求参数按照参数名的字母顺序排序,例如:nonce=abc123×tamp=1622945123。
- 将排序后的参数按照 “参数名 = 参数值” 的格式拼接成一个字符串,例如:nonce=abc123×tamp=1622945123。
- 将拼接后的字符串加上一个密钥(可以是预先约定好的密钥),例如:nonce=abc123×tamp=1622945123&key=secret。
- 对加密后的字符串进行哈希计算,例如使用 MD5 算法,得到一个签名值,例如:c0c3f9a2a4c4c4dcd6d5b7b2a2e4d7b1。将签名值添加到接口请求中,例如:nonce=abc123×tamp=1622945123&signature=c0c3f9a2a4c4c4dcd6d5b7b2a2e4d7b1。
- 在接口服务端对接口请求进行校验时,按照相同的算法计算签名值,并与请求中的签名值进行比对,如果一致,则说明请求合法,否则说明请求不合法。
通过以上步骤,可以有效地防止接口被恶意狂刷的攻击。
理论上,哈希计算很难破解,但是如果攻击者知道了 hash 算法和盐,攻击者就有可能伪造出带有正确校验位的签名值,从而绕过 Java 接口的限流和安全机制。
因此,该方案主要适用于需要简单防范一些低强度攻击的场景,例如防范垃圾请求或非法爬虫等。
对于高强度攻击,建议采取更为复杂的验证策略,例如使用使用用户访问认证,资源访问授权、IP 白名单、签名算法等。
使用 HTTPS
使用 HTTPS 可以保护数据传输的安全性,可以防止恶意攻击者窃取数据。HTTPS 使用 SSL/TLS 协议对数据进行加密,可以确保数据在传输过程中不被篡改或窃取。
因此,在一些恶意狂刷的高频接口,比如短信验证码接口、登录注册入口等敏感区域使用 HTTPS 是必要的。
当然,尽量在客户端和服务端在全部通讯,都使用 HTTPS 协议进行加密,防止数据被窃听或篡改。
用户访问认证
用户访问认证是指在系统中验证用户身份以授权其访问系统资源的过程。
用户访问认证是信息安全中非常重要的一环,可以保护系统免受未经授权的访问和攻击。
常见的用户访问认证方式包括用户名密码认证、双因素认证、证书认证等
这里来看最为简单的 用户访问认证: 用户名密码认证
用户名密码认证 的方式,要求用户提供 用户名和密码,换取 访问的令牌。
参考的代码如下:
@RequestMapping("/api/login")
public String login(@RequestParam("username") String username, @RequestParam("password") String password){
if(!checkUser(username, password)){
return "用户名或密码错误";
}
String token = getToken();
saveToken(token);
return token;
}
private boolean checkUser(String username, String password){
//校验用户是否合法
}
private String getToken(){
//生成token
}