Nginx 安全配置实战:防DDoS、限流与WAF规则编写
Nginx 只能看到自己所在层面的连接、请求、URI、Header、Body 和上游交互结果。 超过这个边界的事情——大带宽 DDoS、链路拥塞、源站前设备被打满——单靠 Nginx 配置解决不了。 核心原则:先分层判断,再做针对性限制。
一、三层攻击防御坐标系
| 攻击类型 | Nginx 可见层级 | 首选能力 | 误用方向 |
|---|---|---|---|
| 大带宽 DDoS | 网络入口之前 | CDN/高防清洗 | 指望 Nginx 单机硬扛 |
| 连接洪泛 | 连接层 | limit_conn、超时、backlog |
只靠 URI 级限流 |
| 请求洪泛 | 请求层 | limit_req |
只看 active connections |
| 扫描/注入探测 | 规则层 | WAF、黑白名单 | 只调连接数 |
| 撞库/爆破 | 接口行为层 | 限速+验证码+账号联动 | 仅按 IP 限制 |
二、先修观测面
2.1 真实源地址恢复(前提)
限流、封禁、黑白名单全部建立在正确源地址之上,否则全部失真。
# /etc/nginx/conf.d/security/realip.conf
set_real_ip_from 10.10.0.0/16;
set_real_ip_from 172.20.0.0/16;
set_real_ip_from 192.168.10.0/24;
real_ip_header X-Forwarded-For;
real_ip_recursive on;
⚠️ 关键: 不要写 0.0.0.0/0,否则任何客户端都能伪造 XFF 绕过限流。
# 验证:第一列应该是真实客户端 IP,而不是代理 IP
tail -n 20 /var/log/nginx/access.security.log | awk '{print $1}'
2.2 日志格式补齐
log_format security_main '$realip_remote_addr [$time_local] '
'"$request" $status $body_bytes_sent '
'rt=$request_time urt=$upstream_response_time '
'uaddr="$upstream_addr" uri="$uri" '
'args="$args" ua="$http_user_agent" '
'xff="$http_x_forwarded_for"';
access_log /var/log/nginx/access.security.log security_main;
关键字段:$realip_remote_addr(真实 IP)、$request_time、$upstream_response_time、$status。
2.3 连接状态页
server {
listen 127.0.0.1:8080;
location /nginx_status {
stub_status;
allow 127.0.0.1;
deny all;
}
}
Active connections 持续高但 QPS 不高 → 慢连接/空闲连接占坑。
三、连接层防护
limit_conn — 并发连接限制
# http 层:定义统计键和内存区
limit_conn_zone $binary_remote_addr zone=conn_per_ip:20m;
# server/location 层:应用
location /admin/ {
limit_conn conn_per_ip 10;
proxy_pass http://admin_backend;
}
常见误改: 全站统一低阈值 → HTTP/2 用户误伤。应该按业务路径拆阈值。
关键超时配置
keepalive_timeout 15;
keepalive_requests 1000;
reset_timedout_connection on;
client_header_timeout 10s;
client_body_timeout 15s;
send_timeout 15s;
四、请求层防护
limit_req — 请求速率限制
# http 层:定义限流区
limit_req_zone $binary_remote_addr zone=req_login:20m rate=5r/s;
limit_req_zone $binary_remote_addr zone=req_sms:20m rate=2r/s;
limit_req_zone $binary_remote_addr zone=req_default:50m rate=30r/s;
# location 层:按接口应用
location = /api/login {
limit_req zone=req_login burst=10 nodelay;
proxy_pass http://auth_backend;
}
location = /api/sms/send {
limit_req zone=req_sms burst=5; # 不加 nodelay:平滑排队
proxy_pass http://sms_backend;
}
nodelay vs 不加:
nodelay→ 超过速率后快速拒绝,适合不允许多次重试的接口- 不加
nodelay→ 短时突刺被延迟处理,用户体验更平滑
分级原则: 对登录、短信、注册等敏感接口用低阈值;对公开 API 用较高阈值。
限流也常出现在踩坑清单中,详见 nginx-config-pitfalls 踩坑点十二「核心接口未做限流」及真实 IP 配置踩坑点十一。
五、规则层防护(原生 WAF)
危险方法拦截
if ($request_method !~ ^(GET|HEAD|POST)$ ) { return 405; }
常见扫描路径拦截
location ~* /(\.git|\.svn|\.env|wp-admin|wp-login\.php|
phpmyadmin|actuator|jenkins|manager/html) {
return 403;
}
恶意 UA 拦截
map $http_user_agent $bad_ua {
default 0;
~*(sqlmap|nmap|nikto|masscan|acunetix|dirbuster|gobuster) 1;
}
server { if ($bad_ua) { return 403; } }
低阶参数特征拦截(必须先用审计模式)
map $query_string $bad_args_audit {
default 0;
~*(union\s+select|sleep\(|benchmark\(|
information_schema|/etc/passwd|<script) 1;
}
# ⚠️ 先审计,不拦截
log_format waf_audit '$time_local ip=$realip_remote_addr '
'uri="$uri" args="$args" hit=$bad_args_audit';
access_log /var/log/nginx/waf_audit.log waf_audit if=$bad_args_audit;
# 确认误伤可控后再升级为拦截
# if ($bad_args_audit) { return 403; }
误杀重灾区: 搜索接口、富文本接口、上传或模板编辑接口。
六、ModSecurity + CRS 接入
# 先「检测」后「拦截」
modsecurity on;
modsecurity_rules_file /etc/nginx/modsec/main.conf;
# main.conf — 先检测
SecRuleEngine DetectionOnly
Include /etc/nginx/modsec/crs/crs-setup.conf
Include /etc/nginx/modsec/crs/rules/*.conf
# 误伤可控后改为
# SecRuleEngine On
精准启用: 只对高风险路径开启,不要全站一把梭。
location /api/ {
modsecurity on;
modsecurity_rules_file /etc/nginx/modsec/api-only.conf;
proxy_pass http://api_backend;
}
七、黑白名单与可信来源
geo $office_allow {
default 0;
203.0.113.0/24 1;
198.51.100.10/32 1;
}
map $office_allow $admin_guard {
0 1;
1 0;
}
location /admin/ {
if ($admin_guard) { return 403; }
proxy_pass http://admin_backend;
}
八、配置目录结构(可独立回滚)
/etc/nginx/
├── nginx.conf
├── conf.d/
│ ├── site.conf
│ └── security/
│ ├── realip.conf # 真实地址恢复
│ ├── rate-limit-zones.conf # 限流区定义
│ ├── waf-maps.conf # WAF 规则 map
│ ├── allow-deny.conf # 黑白名单
│ └── site-policy.conf # 站点级应用策略
└── modsec/
├── main.conf
└── crs/
每层独立回滚: 新 WAF 规则误伤时只回滚 waf-maps.conf,不影响真实 IP 和限流。
九、判断坐标系
| 现象 | 首看指标 | 更可能的问题层 | 第一动作 |
|---|---|---|---|
| active connections 高,QPS 不高 | stub_status, request_time | 连接层 | 调连接限制/超时 |
| 某 URI QPS 高,连接数一般 | URI TopN, IP TopN | 请求层 | limit_req 按接口 |
| 403/444 上升,URI 离散 UA 异常 | access log, 规则命中日志 | 规则层 | 审计扫描特征和黑白名单 |
| 5xx 上升 + upstream_time 高 | upstream 日志 | 上游已满 | 限流入口保护上游 |
| 所有来源像同一 IP | $realip_remote_addr | 地址恢复错误 | 先修 real IP |
关联页面
| 页面 | 关联点 |
|---|---|
| nginx-config-pitfalls | 踩坑点十一(真实 IP)+ 踩坑点十二(限流)的安全配置上下文 |
| nginx-502-504-connection-reset-guide | 上游异常与入口拦截的区别判断 |
| nginx-pre-launch-checklist | 上线前检查(限流项与此文配套) |
| server-security-hardening-checklist | 服务器安全加固总纲(Nginx 加固上下文) |
| rate-limiting-algorithms | 接口限流 5 种算法详解(计数器/滑动窗口/令牌桶/漏桶/Redis+Lua)——限流的算法原理参考 |
| nginx-realtime-push-guide | SSE/WebSocket 推送 — WSS 安全配置参考 |
| nginx-load-balancing-strategy-guide | Nginx 负载均衡策略选择实战指南 — 加权轮询与 IP Hash 深度对比、混合策略最佳实践 |
| nginx-log-analysis-monitoring-guide | Nginx 日志分析与监控体系构建指南 — 自定义日志格式、性能分析技巧、GoAccess 可视化、 |
| nginx-production-performance-optimization | 生产级 Nginx 性能优化 — OS 内核/Worker 进程/HTTP I/O/Upstream |
| network-troubleshooting-order | 防火墙/iptables 与 Nginx 安全联动 |