安全加固实战
安全加固实战
写在前面
Nginx 作为反向代理,经常直接面对公网——所有 HTTP 攻击都先打 Nginx。本篇会讲清楚 Nginx 自身的常见安全配置:防 CC、防 SQL 注入、防路径穿越、限流、防爬虫,以及 ModSecurity WAF 的集成,最后实战公司 API 网关被攻击的真实案例。
一、安全头(基础)
任何 Nginx 服务都必须设置的几个头:
server {
# 防止 MIME 类型嗅探
add_header X-Content-Type-Options "nosniff" always;
# 防止点击劫持
add_header X-Frame-Options "SAMEORIGIN" always;
# XSS 过滤器
add_header X-XSS-Protection "1; mode=block" always;
# CSP - 内容安全策略
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:;" always;
# Referrer
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
# Permissions Policy(替代 Feature-Policy)
add_header Permissions-Policy "geolocation=(), microphone=(), camera=()" always;
# HSTS
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
}
1.1 每个头的含义
X-Content-Type-Options: nosniff— 禁止浏览器猜测 MIME 类型,必须严格匹配 Content-TypeX-Frame-Options: SAMEORIGIN— 禁止被 iframe 嵌入(防点击劫持)X-XSS-Protection: 1; mode=block— 启用浏览器 XSS 过滤Content-Security-Policy— 指定资源加载来源(防 XSS 关键)Referrer-Policy— 控制 Referer 头传递(防信息泄露)Permissions-Policy— 限制哪些 API 可用(摄像头、定位等)Strict-Transport-Security— 强制 HTTPS(上一篇讲过)
1.2 always 关键字
always 让头在所有响应都加上(默认 4xx/5xx 不加)。生产环境永远加 always。
二、限流
2.1 限制请求速率(limit_req)
# http 块定义限流区
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=100r/s;
server {
location /api/ {
limit_req zone=api_limit burst=200 nodelay;
proxy_pass http://backend;
}
}
zone=api_limit:10m:10MB 共享内存,大约 16 万 IPrate=100r/s:每秒 100 个请求burst=200:允许突发到 200(瞬时超出 rate 也能处理)nodelay:超过 burst 立即返回 503,不等排队
2.2 限制连接数(limit_conn)
limit_conn_zone $binary_remote_addr zone=conn_limit:10m;
server {
location /download/ {
limit_conn conn_limit 5; # 每个 IP 最多 5 个并发连接
proxy_pass http://backend;
}
}
2.3 限制下载速度
location /download/ {
limit_rate_after 10m; # 前 10MB 满速
limit_rate 1m; # 之后 1MB/s
}
防止单个下载占满带宽。
2.4 多维限流
基于用户登录态的限流:
# 用 map 把 user ID 转成限流 key
map $cookie_session $limit_key {
default $binary_remote_addr; # 未登录用 IP
~.+ $cookie_session$binary_remote_addr; # 登录用 session + IP
}
limit_req_zone $limit_key zone=user_limit:10m rate=10r/s;
server {
location /api/ {
limit_req zone=user_limit burst=20 nodelay;
}
}
2.5 实战:被攻击时的多级限流
公司 API 网关被攻击时,我们用了多级漏斗:
# 第一级:全局限流(防整体带宽耗尽)
limit_req_zone $binary_remote_addr zone=global_limit:10m rate=1000r/s;
# 第二级:按 IP 限流(防单 IP 攻击)
limit_req_zone $binary_remote_addr zone=ip_limit:10m rate=50r/s;
# 第三级:按 API 限流(防单个接口被打)
limit_req_zone $binary_remote_addr zone=login_limit:10m rate=5r/s;
server {
# 全局
limit_req zone=global_limit burst=2000 nodelay;
location /api/login {
limit_req zone=login_limit burst=10 nodelay; # 登录接口特别严
proxy_pass http://user_service;
}
location /api/ {
limit_req zone=ip_limit burst=100 nodelay;
proxy_pass http://backend;
}
}
效果:单 IP 被攻击时只影响自己的流量,其他用户不受影响。
三、防 CC 攻击
3.1 什么是 CC 攻击
CC(Challenge Collapsar)攻击:用大量真实 IP(可能是肉鸡)对特定 URL 发起大量请求,耗尽后端资源。
特点:
- IP 真实,不容易封
- 请求合法,普通限流可能不够
- 集中在特定 URL
3.2 实战:被攻击的真实案例
时间:2024 年 7 月某个周日
现象:API 网关 CPU 100%,所有接口 P99 延迟 30 秒
日志:某 IP 段对 /api/products/search 发起每秒 5000+ 请求
3.3 第一阶段:紧急止血
# 立即给被攻击的接口加严苛限流
location /api/products/search {
limit_req zone=search_limit burst=20 nodelay;
proxy_pass http://product_service;
}
limit_req_zone $binary_remote_addr zone=search_limit:10m rate=5r/s;
5 分钟内恢复。
3.4 第二阶段:加验证码
被攻击的接口加图形验证码:
location /api/products/search {
# 验证 Referer
if ($http_referer !~ "^https://company.com") {
return 403;
}
# 验证 Cookie(用户必须先访问首页拿到 cookie)
if ($cookie_verified != "yes") {
return 302 https://company.com/captcha;
}
proxy_pass http://product_service;
}
加验证码是终极武器——CC 攻击最大的问题是请求"合法",但加了验证码就逼攻击者做 OCR,攻击成本飙升。
3.5 第三阶段:接入云 WAF
server {
# 把请求转给云 WAF
location / {
proxy_pass https://waf-api.company.com$request_uri;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
阿里云 WAF、Cloudflare 都提供类似的反代模式。
3.6 防 CC 的多层防线
[Cloudflare WAF] ← 7 层过滤
↓
[Nginx limit_req] ← 粗粒度限流
↓
[行为分析] ← 检测异常 IP
↓
[验证码] ← 终极防御
↓
[后端]
四、防 SQL 注入
4.1 Nginx 层能做的有限
Nginx 不是 WAF,不能在 Nginx 配置里写 SQL 注入规则(那需要正则解析 SQL 语法)。
4.2 但可以过滤常见攻击 payload
location / {
# 拦截常见 SQL 注入关键词
if ($request_uri ~* "(union|select|insert|update|delete|drop|truncate|xp_cmdshell|benchmark)") {
return 403;
}
# 拦截常见路径穿越
if ($request_uri ~* "(\.\./|\.\.\\|%2e%2e|%252e%252e)") {
return 403;
}
proxy_pass http://backend;
}
⚠️ 这只是粗过滤,真正的 SQL 注入防御在后端(参数化查询、ORM)。
4.3 用 ModSecurity
ModSecurity 是真正的 WAF,可以解析 HTTP 协议,匹配 OWASP 规则集。
# 安装
apt install libmodsecurity3
# 编译 nginx-modsecurity 或用 OpenResty
# nginx.conf 加载
load_module modules/ndk_http_module.so;
load_module modules/ngx_http_modsecurity_module.so;
server {
modsecurity on;
modsecurity_rules_file /etc/nginx/modsecurity/main.conf;
location / {
proxy_pass http://backend;
}
}
modsecurity/main.conf 启用 OWASP CRS:
SecRuleEngine On
SecRequestBodyAccess On
SecResponseBodyAccess On
SecRule REQUEST_HEADERS:Content-Type "text/xml" \
"id:200000, phase:1, deny, status:403, log, msg:'XML request blocked'"
Include /etc/nginx/modsecurity/owasp-crs/crs-setup.conf
Include /etc/nginx/modsecurity/owasp-crs/rules/*.conf
我们生产用了 ModSecurity + OWASP CRS,有效拦截了 90%+ 的自动化攻击。
五、路径穿越与文件包含
5.1 攻击原理
# 攻击者请求
GET /../../../etc/passwd HTTP/1.1
GET /static/..%2F..%2F..%2Fetc%2Fpasswd
5.2 防护
server {
# 拦截路径穿越
if ($request_uri ~* "(\.\.|%2e%2e|%252e)") {
return 403;
}
# 关键 - alias 必须有结尾 /
location /static/ {
alias /var/www/static/;
}
# NG - 没有结尾 / 会让 /static../etc/passwd 穿过
# location /static {
# alias /var/www/static;
# }
# 文件下载目录 - 禁止执行
location /uploads/ {
types {} default_type application/octet-stream;
root /var/www;
}
}
5.3 关闭不必要的方法
# 只允许 GET / POST / HEAD
if ($request_method !~ ^(GET|POST|HEAD)$) {
return 405;
}
六、隐藏 Nginx 信息
server_tokens off; # 隐藏版本号
more_clear_headers Server; # 用 headers-more 模块,完全删 Server 头
攻击者拿到版本号就能针对性找漏洞。绝对要隐藏。
七、防爬虫
7.1 基于 User-Agent
location / {
if ($http_user_agent ~* "(scrapy|httpclient|scanner|crawler|spider)") {
return 403;
}
proxy_pass http://backend;
}
⚠️ 简单的 UA 过滤很容易被绕过(User-Agent 可任意伪造)。
7.2 行为分析(更可靠)
用 OpenResty + Lua:
-- 每分钟每个 IP 的请求数
local limit = require "resty.limit.req"
local lim = limit.new("user_rate", 100, 100) -- 100 req/s, 100 burst
local key = ngx.var.binary_remote_addr
local delay, err = lim:incoming(key, true)
if not delay then
if err == "rejected" then
return ngx.exit(503)
end
end
7.3 robots.txt
location = /robots.txt {
root /var/www/static;
}
robots.txt 是君子协议,真正的恶意爬虫不遵守。
八、IP 黑名单
8.1 临时封禁
# 黑名单文件
include /etc/nginx/blacklist.conf;
# blacklist.conf 内容
deny 1.2.3.4;
deny 5.6.7.0/24;
8.2 动态黑名单
# 用 geo 模块从变量里读
geo $is_blacklisted {
default 0;
1.2.3.4 1;
5.6.7.0/24 1;
}
server {
if ($is_blacklisted) {
return 403;
}
}
$is_blacklisted 可以从外部文件动态加载:
# /etc/nginx/conf.d/blacklist-geo.conf
geo $is_blacklisted {
default 0;
include /etc/nginx/blacklist-ip.conf;
}
脚本自动添加恶意 IP:
#!/bin/bash
echo "deny $1;" >> /etc/nginx/blacklist-ip.conf
nginx -s reload
8.3 实战:被攻击时的紧急封禁
# 看访问最多的 IP
awk '{print $1}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -20
# 封禁
echo "deny 1.2.3.4;" >> /etc/nginx/blacklist.conf
nginx -t && nginx -s reload
九、安全审计清单
9.1 上线前必查
-
server_tokens off设置 - HTTPS 配置安全(TLS 1.2/1.3、强加密套件、HSTS)
- 安全头全开(X-Content-Type-Options、X-Frame-Options 等)
- limit_req 限流
- 路径穿越防护
- 不必要的方法关闭
- 日志完整,记录客户端 IP 和 UA
9.2 定期检查
- SSL Labs 评分 A+
- 错误日志没有异常请求
- access 日志分析异常 IP
- 证书过期时间监控
- WAF 规则更新
十、本篇小结
| 攻击类型 | 防御手段 |
|---|---|
| CC 攻击 | 多级 limit_req + 验证码 + WAF |
| SQL 注入 | Nginx 粗过滤 + WAF + 后端参数化 |
| 路径穿越 | Nginx location + alias + 过滤 |
| 爬虫 | UA 过滤 + 行为分析 + robots.txt |
| 暴力破解 | 单独接口限流 + 验证码 |
| 带宽耗尽 | limit_rate + CDN |
下一篇讲 性能调优与高并发,怎么把单机 Nginx 调到 10w 并发。