一、核心风险说明
免鉴权接口(登录、验证码、注册、健康检查、公开查询等)无 token 校验,常见攻击:
- 暴力破解(登录密码 / 验证码爆破)
- 高频刷接口(短信轰炸、注册灌水、DoS)
- SQL 注入、XSS、路径遍历
- 爬虫批量拉取公开数据
- IP 恶意请求、CC 攻击
- 越权、参数篡改、重放攻击
防护分三层:Nginx 层前置拦截(低成本、高性能) + SpringBoot 应用层校验(业务逻辑防护) + 基础设施兜底。
二、Nginx 层防护(优先做,不占用 Java 服务资源)
1. 单 IP 限流,防高频刷接口(CC / 短信轰炸)
对所有免登接口单独配置限流,区分普通接口 / 验证码 / 登录接口(验证码限流更严)
# 全局限流配置 http块
http {
# 按IP限流,10M内存存储IP
limit_req_zone $binary_remote_addr zone=free_api:10m rate=10r/s;
# 验证码单独限流,更严格
limit_req_zone $binary_remote_addr zone=code_api:10m rate=1r/3s;
# 登录接口限流
limit_req_zone $binary_remote_addr zone=login_api:10m rate=2r/m;
}
server {
location /api/login {
limit_req zone=login_api burst=3 nodelay;
proxy_pass http://springboot;
}
location /api/sendCode {
limit_req zone=code_api burst=1 nodelay;
}
# 所有免鉴权接口统一限流
location ~ ^/api/(public|register|health) {
limit_req zone=free_api burst=5 nodelay;
proxy_pass http://springboot;
}
}
参数说明:
$binary_remote_addr:这是 Nginx 的一个内置变量,表示客户端的 IP 地址(二进制格式)。- zone=free_api:10m:定义一个名为 free_api 的共享内存区域,大小为 10 MB。
rate=1r/3s:每 3 秒最多 1 次请求burst:突发缓冲队列,超出直接返回 503nodelay:队列请求立即处理,不延迟排队
1.1 zone=free_api:10m
| 部分 | 说明 |
|---|---|
zone |
关键字,表示定义一块共享内存区域 |
free_api |
自定义名称,在后续 limit_req 指令中引用它 |
10m |
内存大小为 10 MB(m 代表兆字节) |
内存能存储多少数据?
-
Nginx 使用高效的哈希表存储每个 IP 的访问状态
-
每个 IP 大约占用 32-64 字节
-
10 MB ≈ 能存储 15万-30万个 不同的 IP 地址
-
当内存用满时,Nginx 会移除最旧的记录(LRU 策略)。如果日活用户 100万,这会导致旧的IP记录被频繁淘汰,限流失效。
选择多大内存合适?
# 小型业务(日活 < 1万)
zone=free_api:1m
# 中等业务(日活 1万-50万)
zone=free_api:10m
# 大型业务(日活 > 50万)
zone=free_api:50m
1.2 rate=10r/s
| 部分 | 说明 |
|---|---|
rate |
关键字,定义速率限制 |
10r |
10 个请求(r = request) |
/s |
每秒(per second),也可以使用 /m(每分钟) |
常用速率示例:
# 每秒 1 个请求(适合防止暴力破解登录接口)
rate=1r/s;
# 每分钟 60 个请求(等价于每秒1个,但允许突发)
rate=60r/m;
# 每秒 100 个请求(适合高并发公开API)
rate=100r/s;
重要概念:速率是如何计算的?
-
基于 令牌桶算法(Token Bucket)
-
Nginx 会以固定速率(每秒 10 个)往桶中添加令牌
-
每个请求需要消耗 1 个令牌
-
令牌耗尽后,新请求会被延迟或拒绝
2. IP 黑名单 + 临时封禁(爆破拦截)
配合限流自动拉黑恶意 IP,使用 nginx lua/deny,或定时脚本同步攻击 IP
# 封禁恶意IP列表
deny 192.168.1.100;
# 允许内网
allow 127.0.0.1;
allow 192.168.1.0/24;
deny all;
3. 请求参数过滤,拦截注入攻击
Nginx 匹配 URL / 参数关键字,拦截 SQL 注入、XSS、路径遍历
if ($query_string ~* "union|select|and|or|alert|<script>|../") {
return 403;
}
# 拦截异常请求方法
if ($request_method !~ ^(GET|POST)$ ) {
return 405;
}
# 限制请求体大小,防大报文DoS
client_max_body_size 10k;
4. 伪造 IP 防护(必须配置,避免黑客伪造 X-Forwarded-For 绕过限流)
如果前端有 CDN / 负载均衡,正确取真实客户端 IP,防止伪造 IP 无限刷接口:
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# 信任CDN内网IP,防止伪造XFF
real_ip_header X-Forwarded-For;
set_real_ip_from 10.0.0.0/8;
5. 验证码 / 登录接口增加人机校验拦截
Nginx 拦截无验证码、无滑块票据的请求,结合前端传入captchaId参数校验,无则 403。
6. 关闭敏感头、防信息泄露
server_tokens off; # 隐藏nginx版本
proxy_hide_header Server;
add_header X-Frame-Options DENY;
add_header X-XSS-Protection "1; mode=block";
add_header X-Content-Type-Options nosniff;
三、SpringBoot 应用层防护(业务级安全,Nginx 挡不住的恶意请求)
1. 接口粒度区分免鉴权路径(统一拦截器 / 过滤器)
使用 Spring Security / 自定义 Filter,白名单放行免登接口,其余强制 token;禁止全局开放。
Spring Security 示例
@Configuration
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.authorizeHttpRequests(auth -> auth
// 免鉴权白名单
.requestMatchers("/api/login", "/api/sendCode", "/api/public/**", "/actuator/health").permitAll()
// 其他全部需要认证
.anyRequest().authenticated()
);
return http.build();
}
}
2. 业务层限流(分布式场景,Nginx 单机限流失效补充)
使用 Redis 实现分布式 IP 限流,针对登录、验证码做次数限制:
- 同一 IP 1 分钟最多 5 次登录失败,锁定 10 分钟
- 同一手机号 1 分钟最多 1 条验证码,1 天上限 10 条
伪代码示例:
// 登录失败计数
String key = "login:fail:" + ip;
Long count = redisTemplate.opsForValue().increment(key, 1);
if(count == 1) redisTemplate.expire(key, 10, TimeUnit.MINUTES);
if(count > 5) return "登录过于频繁,请稍后再试";
3. 人机验证(核心防刷手段)
所有高危免登接口强制人机校验:
- 图形验证码(登录 / 注册)
- 滑块 / 行为验证码(极验、阿里云验证码)
- 设备指纹:前端采集浏览器指纹、UA、设备 ID 上传后台校验。
无合法验证码票据直接拒绝业务处理。
4. 请求参数强校验(防注入、越权)
使用 Hibernate Validator 全局校验所有入参:
-
手机号、邮箱长度、格式正则校验
-
ID、数字参数限制数值范围
-
禁止特殊字符、脚本标签传入
@PostMapping("/sendCode") public Result sendCode(@NotBlank @Pattern(regexp = "^1[3-9]\\d{9}$") String phone) { // 业务逻辑 }
全局异常拦截非法参数请求,记录攻击日志。
5. 防重放攻击(公开查询接口)
给前端分配临时签名参数 timestamp + nonce + sign:
- 前端用密钥对参数 + 时间戳加密生成 sign
- 后端校验:时间戳 5 分钟内有效、nonce 一次性存入 Redis 去重、sign 校验一致 防止抓包后重复调用免登接口拉取数据。
6. 敏感操作风控规则
- 同一 IP 短时间大量注册账号 → 拒绝注册
- 异地高频登录 → 二次验证
- 批量查询接口增加分页上限,禁止一次性查全量数据
7. 全局异常日志 + 攻击记录
拦截所有 400、403、限流、参数非法请求,记录:IP、接口、参数、UA,定时统计恶意 IP 推送告警。
四、分布式 / 集群补充方案
- **Redis 分布式限流:**多台 Nginx、多 SpringBoot 实例时,单机 Nginx 限流失效,统一用 Redis 存储 IP 访问计数。
- **CDN/WAF 前置防护:**阿里云 WAF、Cloudflare 等云 WAF:内置 CC 防护、SQL 注入、爬虫识别、验证码拦截,最省心。
- 接口灰度频次控制:公开数据接口做分档 QPS 限制:普通访客低并发,登录用户放开额度。
五、不同免鉴权接口差异化防护策略
| 接口类型 | 核心攻击 | 防护重点 |
|---|---|---|
| 登录接口 | 密码暴力破解 | 登录失败计数封禁、人机验证、IP 限流 |
| 短信验证码 | 短信轰炸 | 手机号 + IP 双重限流、每日上限 |
| 注册接口 | 灌水批量注册 | 设备指纹、滑块验证码、IP 频次 |
| 公开查询接口 | 爬虫批量爬取 | 签名防重放、分页限制、IP 限流 |
| 健康检查 / 监控 | 扫描探测 | 内网 IP 白名单,外网直接禁止访问 |
六、最简落地执行顺序
- Nginx 配置 IP 限流、请求过滤、真实 IP 解析(第一层拦截)
- SpringSecurity 严格配置免登白名单,杜绝越权开放接口
- 登录 / 验证码接入人机验证码,增加 Redis 业务限流
- 所有入参统一校验,增加时间戳签名防重放
- 接入 WAF / 防火墙兜底,开启攻击日志告警
- 定期清理、拉黑高频恶意 IP
七、常见踩坑点
- 只在应用层限流,没做 Nginx 前置:大量无效请求打满 Java 线程池,服务雪崩
- X-Forwarded-For 未正确配置,黑客伪造 IP 绕过限流
- permitAll 配置 /**,误开放所有接口,造成越权漏洞
- 验证码仅前端校验,后端不二次校验,黑客绕过前端直接调用接口
- 单机 Nginx 集群部署,未做分布式 Redis 限流,限流失效