大家好,我是程序员柏风,AI 最全的 Vibecoding 学习地图 http://coderoadmap.cn 作者。
纵深防御:WAF、IDS 与接口防刷
这一课你将能做到
- 给 Spring Boot 平台的登录与核心接口加上多层限流(Nginx + 应用内 Bucket4j)
- 部署 ModSecurity + OWASP CRS 感受 WAF 的拦截与绕过博弈
- 用 Suricata 在自建靶场检测一次端口扫描,理解 IDS 的规则机制
为什么要学
代码修复是根本,但线上环境永远有改不完的旧代码和躲不开的 0day。WAF、IDS、限流是挡在业务前面的缓冲层:限流保证「被刷不死」,WAF 拦截「已知攻击模式」,IDS 负责「发现有人在踩点」。三者加上代码修复,才构成纵深防御。
本站平台的真实场景:登录接口被脚本撞库、详情页被爬虫打挂、注册接口被批量薅羊毛——第一响应手段全是限流,而不是等代码排期。
先建立图像
攻击流量 ▼
┌────────────────────────────────────────────┐
│ CDN/高防:吸收大流量 DDoS │ ← 流量层
│ WAF(Nginx+ModSecurity/云WAF):拦注入、扫描器 │ ← 应用层规则
│ 网关限流:按 IP/用户/接口 限速 │ ← 行为控制
│ IDS(Suricata):旁路检测,告警不拦截 │ ← 感知层
│ Spring Boot:业务校验 + 应用内限流兜底 │ ← 最后一道
└────────────────────────────────────────────┘
日志 ↑ 每一层都输出,SIEM 汇聚分析
跟着做
步骤 1:Nginx 层限流(连接数 + 请求速率)
# nginx.conf http 段
limit_req_zone $binary_remote_addr zone=login:10m rate=5r/m; # 每IP登录5次/分
limit_conn_zone $binary_remote_addr zone=conn:10m;
server {
location /api/auth/login {
limit_req zone=login burst=3 nodelay; # 突发只放3个
limit_conn conn 5;
proxy_pass http://127.0.0.1:8080;
}
}
# 压测验证(打本机)
ab -n 100 -c 10 http://localhost/api/auth/login
# 观察 503 响应比例
步骤 2:应用内限流(Bucket4j,按用户维度)
// Maven: com.bucket4j:bucket4j-core
Bucket bucket = Bucket.builder()
.addLimit(Bandwidth.classic(30, Refill.greedy(30, Duration.ofMinutes(1))))
.build();
@PostMapping("/api/comment")
public ResponseEntity<?> comment(@RequestBody CommentReq req, Authentication auth) {
if (!bucket.tryConsume(1)) { // 以 userId 维度建桶更准确
return ResponseEntity.status(429)
.header("Retry-After", "60").body("操作过于频繁");
}
return ResponseEntity.ok(service.save(req));
}
多实例部署把桶放进 Redis(Bucket4j-Redis),全局一致计数。
步骤 3:WAF——ModSecurity + OWASP CRS
# Ubuntu 上给 Nginx 装 ModSecurity v3
sudo apt install libmodsecurity3 modsecurity-nginx
# 拉取 OWASP 核心规则集
git clone https://github.com/coreruleset/coreruleset.git /etc/nginx/crs
cp /etc/nginx/crs/crs-setup.conf.example /etc/nginx/crs/crs-setup.conf
# nginx.conf 加载规则后,发一个探测请求验证:
curl "http://localhost/?id=1%20UNION%20SELECT%201,2,3--"
# 期望返回 403,error.log 出现 [id "942100"] 拦截记录
步骤 4:IDS——Suricata 检测扫描行为
# 靶机安装 Suricata,监听 Host-Only 网卡
sudo apt install suricata
# 自定义规则:检测 nmap SYN 扫描( /etc/suricata/rules/local.rules )
echo 'alert tcp any any -> $HOME_NET any (msg:"SYN Scan detected"; flags:S; \
detection_filter:track by_src, count 20, seconds 10; sid:1000001; rev:1;)' \
| sudo tee /etc/suricata/rules/local.rules
sudo suricata -c /etc/suricata/suricata.yaml -i eth1
# 攻击机执行 nmap -sS 192.168.56.101,查看告警
sudo tail -f /var/log/suricata/fast.log
步骤 5:把日志串起来(Java 侧)
# logback:结构化访问日志 + 关键安全事件单独落盘
logging.structured.format.file=ecs
// 登录失败、限流触发、鉴权失败 → 单独的 security.log,带 traceId 便于串联
log.warn("LOGIN_FAILED ip={} user={} traceId={}", ip, username, MDC.get("traceId"));
讲清楚要点
- 限流要分层且分维度:网络层挡洪峰(Nginx limit_conn)、应用层按业务维度(userId、接口、租户)。只按 IP 限流会误伤公司出口 NAT 后的大量真实用户,只按用户限流拦不住未登录刷接口。
- WAF 是规则博弈,不是银弹:CRS 覆盖注入、扫描器、协议异常,但编码混淆(
%2527双重编码)、大小写、注释符都能绕。WAF 的定位是「给修复争取时间」,误报需要持续调白名单。 - IDS 旁路部署,重在感知:Suricata/Snort 镜像流量只告警不阻断,适合发现慢速扫描、异常外联;要阻断需要 IPS(串联)或与防火墙联动封 IP。
- 429 要带 Retry-After:限流触发的响应给出恢复时间,既是规范也是体验;同时限流事件必须留日志,它是撞库攻击最早的可观测信号。
- 纵深防御的本质是「假设每层都会失效」:WAF 被绕过时还有应用校验;应用出洞时还有 DB 最小权限;DB 沦陷时还有备份与加密。设计时问自己:这层被绕过后,下一层是什么?
你可能会懵的地方
-
WAF 和 IDS 什么区别? WAF 串在流量路径上做 HTTP 深度检测并可拦截(IPS 性质);IDS 通常旁路镜像,跨协议检测并告警。一个在门上,一个是走廊监控。
-
限流阈值怎么定? 用压测与真实流量分布定:P95 用户正常行为的 5-10 倍作为阈值起点,再结合容量上限。关键是监控触发量——触发率突然上涨往往就是攻击信号。
-
CRS 误报太多怎么办? 按「先检测模式(只记日志)→ 分析误报规则 ID → 针对性白名单(按接口与参数)→ 再开拦截」的顺序灰度上线,绝不直接全量拦。
-
Suricata 和 Snort 选哪个? 新部署倾向 Suricata:多线程性能好、支持 EVE JSON 输出便于接入 ELK。Snort 3 也在改进,规则语法基本互通,人才储备上两者通用。
-
云上还需要自建 WAF/IDS 吗? 中小团队直接用云 WAF + 云安全中心更划算;自建的价值在深度定制与私有化合规要求。重点是无论自建还是云,规则都要有人持续运营。
错法对照
| 错法 | 问题 | 正解 |
|---|---|---|
| 只按 IP 限流 | NAT 出口误伤真实用户 | IP + userId + 接口 多维组合 |
| WAF 上线即拦截模式 | 误报打断正常业务 | 先检测模式灰度,白名单调优后再拦 |
| IDS 告警无人看 | 等于没部署 | 告警分级 + 值班响应机制 |
| 限流不加监控 | 攻击发生时毫无感知 | 429 触发量接入告警 |
| 单机内存计数限流 | 多实例各算各的,阈值翻倍 | Redis 集中式计数 |
卡点急救
- ModSecurity 编译/加载报错:版本兼容问题(连接器与 libmodsecurity 要匹配)。优先用发行版包管理器装的组合,自定义编译先在测试机验证。
- Suricata 看不到流量:网卡选错或没镜像流量。Host-Only 场景确认监听实际接口名(
ip a);交换机环境需要配置镜像口。 - Nginx limit_req 生效但全返回 503:burst 太小。正常用户也可能触发,调成
burst适度放宽 +nodelay观察误伤率,并确认 503 页面体验(友好文案)。
面试常问
-
接口被恶意刷,你的完整处置链路? 应急(Nginx/网关临时封禁 + 限流收紧)→ 定位(日志按 IP/UA/指纹聚合,判断撞库/爬虫/CC)→ 加固(按维度限流、验证码、行为风控)→ 根治(业务侧加签名、设备指纹)→ 沉淀(规则进 WAF、触发进告警)。顺序体现优先级:先止血再治病。
-
WAF 的原理与局限性? 基于规则(正则/签名)或语义分析检测 HTTP 异常。局限:编码绕过、0day 无规则、误报需运营。正确定位:纵深防御的一层,不能替代代码修复。
-
为什么限流要按用户维度而不是只按 IP? 办公网/移动网络 NAT 后多用户共享出口 IP,按 IP 限流误伤;攻击者又能换 IP 绕过单 IP 阈值。按已认证 userId(或匿名会话指纹)限流更贴近业务语义,两层叠加才完整。
自测三问
- 画出你平台的纵深防御层次,每层失效后下一层是什么?
- 限流应该按哪几个维度设计?各自解决什么问题?
- CRS 上线为什么要走「检测模式 → 白名单 → 拦截」的灰度?
小结一句话
纵深防御是「假设每层都会被绕过」的工程:限流保可用、WAF 拦已知、IDS 给感知、代码修复除根因,四者缺一不可。
延伸
- OWASP ModSecurity 核心规则集
- Suricata 官方文档
- 下一课:事件响应——NIST/SANS 流程与一次完整的演练。