CC防护的本质不是买设备或者装面板,而是在攻击流量抵达业务逻辑之前,用最低成本识别并丢弃它。很多人以为基础CC防护需要WAF、需要Nginx Plus、需要Lua脚本,实际上用Nginx原生模块和几行配置就能挡掉相当一部分自动化攻击。下面直接讲配置逻辑和可落地的代码。
先理解CC攻击的流量特征
CC攻击不同于带宽型DDoS,它通常表现为大量正常请求打向同一个或几个URL,请求本身合法,但频率异常高。攻击者往往固定User-Agent、固定IP段、固定请求路径,甚至不带Cookie。因此基础防护的核心思路是:限制单IP请求频率、识别异常客户端特征、对可疑流量直接返回444或503。
Nginx提供了两个关键模块:ngx_http_limit_req_module和ngx_http_limit_conn_module。前者限制请求速率,后者限制并发连接数。配合map和if判断,可以做到不依赖第三方组件的基础CC拦截。
核心配置一:限制单IP请求速率
在Nginx的http块中定义限速规则:
http {
limit_req_zone $binary_remote_addr zone=cc_zone:10m rate=20r/s;
limit_req_status 444;
server {
listen 80;
server_name example.com;
location / {
limit_req zone=cc_zone burst=30 nodelay;
proxy_pass http://backend;
}
}
}
这里rate=20r/s表示每个IP每秒最多20个请求。burst=30是允许的突发队列长度,nodelay让突发请求立即处理而不是排队。超过限制的请求直接返回444,Nginx会直接断开连接,不返回任何内容,减少响应开销。10m的共享内存大约可以存储16万个IP的状态,中小站点足够使用。
这个配置的独到之处在于limit_req_status设置成444。很多教程用503,但503会返回错误页,攻击者依然能消耗服务器资源。444是Nginx自定义的非标准状态码,连接直接关闭,攻击端往往收不到完整响应,能有效降低攻击工具的持续性。
核心配置二:限制单IP并发连接数
有些CC工具不是高频请求,而是慢速建立大量连接占用资源。此时需要限制并发:
http {
limit_conn_zone $binary_remote_addr zone=conn_zone:10m;
server {
location / {
limit_conn conn_zone 10;
limit_conn_status 503;
proxy_pass http://backend;
}
}
}
limit_conn conn_zone 10表示同一IP同时最多10个连接。超过后返回503。这个参数需要根据业务调整,如果是API服务可以设小一点,如果是网页浏览可以适当放大。并发限制和速率限制配合使用,能覆盖大多数基础CC场景。
核心配置三:识别并拦截异常User-Agent
大量CC工具使用默认UA或者空UA,通过map可以快速拦截:
http {
map $http_user_agent $is_bad_ua {
default 0;
"" 1;
"~*python" 1;
"~*curl" 1;
"~*wget" 1;
"~*scrapy" 1;
"~*httpclient" 1;
"~*okhttp" 1;
"~*go-http-client" 1;
"~*libwww-perl" 1;
}
server {
location / {
if ($is_bad_ua = 1) {
return 444;
}
proxy_pass http://backend;
}
}
}
这个配置将空UA和常见编程语言HTTP库的UA特征直接标记为恶意。正常浏览器不会使用这些UA访问网站。需要注意的是,某些合法RSS阅读器或监控工具可能使用curl,如果业务依赖这些来源,需要单独加白名单IP或者调整规则。
核心配置四:限制特定URL的访问频率
CC攻击通常集中在登录、搜索、API接口等消耗资源的URL。针对这些路径单独设置更严格的限速:
http {
limit_req_zone $binary_remote_addr zone=login_zone:10m rate=5r/m;
limit_req_zone $binary_remote_addr zone=api_zone:10m rate=50r/s;
server {
location /login {
limit_req zone=login_zone burst=3 nodelay;
limit_req_status 444;
proxy_pass http://backend;
}
location /api/ {
limit_req zone=api_zone burst=20 nodelay;
limit_req_status 444;
proxy_pass http://backend;
}
}
}
登录接口限制为每分钟5次,API接口限制为每秒50次。这种差异化配置比全局一刀切更合理,既保护了高消耗接口,又不影响普通页面浏览。攻击者如果打登录接口,很快就会被封禁。
核心配置五:利用Cookie识别真实用户
CC攻击工具往往不处理Cookie,或者每次请求都不携带Cookie。可以通过判断Cookie是否存在来区分真实用户和自动化工具:
http {
map $http_cookie $is_real_user {
default 0;
"~*sessionid" 1;
}
server {
location / {
if ($is_real_user = 0) {
limit_req zone=cc_zone burst=5 nodelay;
}
proxy_pass http://backend;
}
}
}
这个配置的逻辑是:没有携带sessionid Cookie的请求,限速更严格。正常用户登录后浏览器会带上Cookie,而攻击脚本通常不会维护Cookie。不过这个方案需要业务系统确实设置了名为sessionid的Cookie,实际部署时要根据真实Cookie名称调整。
核心配置六:自动封禁高频攻击IP
单纯的限速只能丢弃请求,攻击IP依然会持续发送流量。更主动的做法是识别高频IP并直接封禁一段时间。Nginx没有内置这个功能,但可以通过日志分析和iptables配合实现。这里给一个轻量级方案:
# 定义自定义日志格式,记录请求频率
http {
log_format cc_format '$remote_addr $request_uri $status $time_local';
server {
location / {
limit_req zone=cc_zone burst=30 nodelay;
limit_req_status 444;
access_log /var/log/nginx/cc.log cc_format;
proxy_pass http://backend;
}
}
}
然后配合一个简单的shell脚本定时分析日志:
#!/bin/bash
# 每分钟执行一次,封禁请求超过200次的IP
tail -n 5000 /var/log/nginx/cc.log | awk '{print $1}' | sort | uniq -c | sort -rn | while read count ip; do
if [ $count -gt 200 ]; then
iptables -I INPUT -s $ip -j DROP
echo "$(date) blocked $ip with $count requests" >> /var/log/nginx/block.log
fi
done
这个脚本统计最近5000条日志中每个IP的请求次数,超过200次就直接用iptables封禁。封禁发生在网络层,比Nginx层更彻底,CPU消耗更低。不过要注意设置封禁有效期,否则可能误伤NAT出口的合法用户。可以配合at命令或者定时任务定期清理iptables规则。
完整配置示例
将上述所有策略整合到一个完整的Nginx配置中:
http {
# 限速区域定义
limit_req_zone $binary_remote_addr zone=global_zone:10m rate=30r/s;
limit_req_zone $binary_remote_addr zone=login_zone:10m rate=5r/m;
limit_req_zone $binary_remote_addr zone=api_zone:10m rate=50r/s;
limit_conn_zone $binary_remote_addr zone=conn_zone:10m;
# 恶意UA识别
map $http_user_agent $is_bad_ua {
default 0;
"" 1;
"~*python" 1;
"~*curl" 1;
"~*wget" 1;
"~*scrapy" 1;
"~*httpclient" 1;
"~*okhttp" 1;
"~*go-http-client" 1;
}
# 真实用户识别
map $http_cookie $is_real_user {
default 0;
"~*sessionid" 1;
}
server {
listen 80;
server_name example.com;
access_log /var/log/nginx/cc.log;
# 全局并发限制
limit_conn conn_zone 15;
limit_conn_status 503;
# 拦截恶意UA
if ($is_bad_ua = 1) {
return 444;
}
location / {
limit_req zone=global_zone burst=40 nodelay;
limit_req_status 444;
proxy_pass http://backend;
}
location /login {
limit_req zone=login_zone burst=3 nodelay;
limit_req_status 444;
proxy_pass http://backend;
}
location /api/ {
limit_req zone=api_zone burst=20 nodelay;
limit_req_status 444;
proxy_pass http://backend;
}
}
}
这套配置不需要安装任何额外软件,纯Nginx原生能力就能实现基础CC防护。实际部署时需要注意几个细节:limit_req_zone的rate要根据业务真实流量调整,设置过低会误伤正常用户;burst参数不宜过大,否则攻击者可以利用突发队列绕过限制;444状态码虽然有效,但某些监控系统可能无法识别,需要调整告警规则。
对于更复杂的CC攻击,比如分布式代理池攻击、慢速攻击、TLS层攻击,这套基础配置就不够用了。但作为第一道防线,它能在攻击初期就过滤掉大量垃圾流量,为上层防护争取时间。而且配置简单、资源消耗极低,任何Nginx服务器都可以快速部署。
