深夜 CPU 飙高,access.log 里同一个 IP 一秒十几个请求,全是打首页或某个重接口——这就是 CC 攻击的典型画面:不需要大带宽,用看似正常的请求把你的 PHP 进程池和数据库耗干。小站被 CC 打压太常见了,好在防护组合拳很成熟:Nginx 的 limit_req 做第一道限流,fail2ban 盯着限流日志封 IP,两层联动,自动挡自动封。
先上 Nginx 限流。limit_req_zone 定义计数区,limit_req 在 location 里启用。rate 是长期平均速率,burst 是允许的突发排队量,nodelay 决定突发请求是排队等待还是直接放行。参数怎么定?按你站点真实用户行为来:正常人不会一秒访问同一路径五次,rate 设到每秒 5 个对正常用户毫无感知,对攻击脚本就是墙。
# http 块:按客户端 IP 建一个 10MB 的计数区(约可存 16 万个 IP 状态)
limit_req_zone $binary_remote_addr zone=perip:10m rate=5r/s;
server {
location / {
limit_req zone=perip burst=10 nodelay;
limit_req_status 503; # 被限流时返回 503,别用默认 502
# 其余配置……
}
}
limit_req 触发时会在 error.log 里留下一句特征日志:limiting requests, excess: xxx by zone "perip",带客户端 IP。这句日志就是 fail2ban 的眼睛——攻击者换着 IP 打,单个 IP 只触发一两次限流,Nginx 层只能削峰;但打压力度一大,同 IP 反复触发限流,fail2ban 抓到 10 次就直接防火墙封禁,连 Nginx 的门都省了。
# /etc/fail2ban/filter.d/nginx-limit-req.conf(特征匹配限流日志)
[Definition]
failregex = limiting requests, excess:.* by zone .*, client: <HOST>
ignoreregex =
# /etc/fail2ban/jail.local(别改 jail.conf,用 .local 覆盖)
[nginx-limit-req]
enabled = true
port = http,https
filter = nginx-limit-req
logpath = /var/log/nginx/error.log
maxretry = 10
findtime = 60
bantime = 24h
# 生效并验证
fail2ban-client reload
fail2ban-client status nginx-limit-req
验证方法直接用 ab 打自己:ab -n 100 -c 20 https://你的域名/,压测期间 Nginx 会开始返回 503,error.log 出现 limiting requests 日志;一分钟后 fail2ban-client status 的 Banned IP list 里应该出现你的测试机 IP。看到这两步,整条防线就算验通了。注意压测完把测试机 IP 加进 fail2ban 的 ignoreip 或者手动 unban,别把自己锁外面。
三个补强建议收尾:一是忽略白名单,CDN 回源 IP 段和自家监控要放进 geo 白名单,否则限流会误伤正常流量;二是 bantime.increment 开上,惯犯封禁时间指数递增,比固定时长更省心;三是把 access.log 的 IP 请求频次做成每日巡检,很多时候小流量打压持续几天才被注意到,巡检能提前发现苗头。限流挡突发、fail2ban 封惯犯、巡检找苗头,三层各司其职,小站的 CC 防护就立住了。
相关阅读:CC 攻击是接入层的安全类故障。《服务器故障排查总纲:按现象反查的五层定位法》把打压、挂马、被墙这些安全事件单独归了类,出事先看总纲的应急处置顺序,再进单篇。
A5创业网 版权所有