适用场景
本文面向Nginx运维工程师、Web安全管理员和自建站站长,专注于防御Slowloris慢速攻击。Slowloris利用HTTP协议特性,以极低速率发送不完整的HTTP请求头部,耗尽服务器连接池,导致正常用户无法访问。本文提供Nginx + iptables + Fail2ban三层防护方案。
前置条件
- Linux服务器(Ubuntu 20.04+ / CentOS 7+),Nginx 1.18+
- root 或 sudo 权限以修改Nginx配置和iptables规则
- 已安装Fail2ban(如未安装可参考之前发布的Fail2ban配置教程)
- 了解HTTP请求头和TCP三次握手基本概念
原理说明
Slowloris攻击由Robert “RSnake” Hansen于2009年首次公开。攻击原理:攻击者建立大量TCP连接后,不断发送不完整的HTTP请求头(每次只发送1个字节的额外头部,如X-a: b\r\n),使服务器持续等待请求完成,直到耗尽max_clients连接上限。传统DDoS防御方案通常关注大流量,而Slowloris流量极小,因此需要专用配置。
操作步骤
第一步:Nginx核心参数调优
编辑 /etc/nginx/nginx.conf 的 http 块,配置以下关键参数:
http {
# 关闭非活动连接的超时时间(秒)— 默认75,调低后 Slowloris 连接更快释放
keepalive_timeout 15;
# 客户端请求头超时时间(秒)— 从第一个字节到完整头部的最长等待
client_header_timeout 10;
# 客户端请求体超时时间(秒)
client_body_timeout 10;
# 发送响应给客户端的超时时间(秒)
send_timeout 10;
# 限制单个客户端最大并发连接数(需 ngx_http_limit_conn_module)
limit_conn_zone $binary_remote_addr zone=addr:10m;
limit_conn addr 20;
# 缓冲区设置 — 防止大包头攻击
client_body_buffer_size 128k;
client_header_buffer_size 1k;
large_client_header_buffers 4 8k;
}
第二步:增加Nginx连接数监控与自动释放
在需要保护的server块中,添加ngx_http_limit_req_module限速:
server {
listen 80;
listen 443 ssl;
server_name yourdomain.com;
# 请求速率限制 — 每秒最多5个请求
limit_req_zone $binary_remote_addr zone=sLowloris:10m rate=5r/s;
limit_req zone=sLowloris burst=10 nodelay;
location / {
proxy_pass http://backend;
proxy_http_version 1.1;
proxy_set_header Connection "";
}
}
第三步:iptables连接数限制
使用connlimit模块限制每个IP的并发连接数,在Slowloris攻击到达Nginx之前即在TCP层拦截:
# 限制每个IP的并发HTTP连接数为30
iptables -A INPUT -p tcp --dport 80 -m connlimit --connlimit-above 30 -j REJECT --reject-with tcp-reset
iptables -A INPUT -p tcp --dport 443 -m connlimit --connlimit-above 30 -j REJECT --reject-with tcp-reset
# 限制每秒新建连接数(防SYN Flood + Slowloris混合攻击)
iptables -A INPUT -p tcp --dport 80 -m state --state NEW -m recent --set --name HTTP
iptables -A INPUT -p tcp --dport 80 -m state --state NEW -m recent --update --seconds 1 --hitcount 10 --name HTTP -j DROP
# 保存规则
apt-get install -y iptables-persistent # Ubuntu
netfilter-persistent save
# CentOS 使用:
# yum install -y iptables-services
# service iptables save
第四步:Fail2ban自定义规则检测Slowloris
Fail2ban通过分析Nginx访问日志来识别Slowloris攻击特征——长时间未完成请求的连接:
# 创建Fail2ban过滤器 /etc/fail2ban/filter.d/nginx-slowloris.conf
[Definition]
failregex = ^<HOST> -.*"(GET|POST).*HTTP/1\.[01]" 499 .*$
ignoreregex =
创建监狱配置 /etc/fail2ban/jail.d/nginx-slowloris.conf:
[nginx-slowloris]
enabled = true
port = http,https
filter = nginx-slowloris
logpath = /var/log/nginx/access.log
maxretry = 20
findtime = 60
bantime = 3600
action = iptables[name=Slowloris, port=http, protocol=tcp]
重启Fail2ban:
systemctl restart fail2ban
fail2ban-client status nginx-slowloris
配置验证
# 1. 验证Nginx配置语法
nginx -t
# 2. 重载Nginx
systemctl reload nginx
# 3. 使用slowloris测试脚本验证防御效果
git clone https://github.com/llaera/slowloris-test.git
cd slowloris-test
python3 slowloris.py -s yourdomain.com -p 443
# 4. 监控Nginx连接状态
netstat -an | grep :80 | wc -l
# 正常情况应在 30 以内,被攻击时该值不应超过设定的 limit_conn 上限
# 5. 查看Fail2ban封禁日志
fail2ban-client status nginx-slowloris
常见问题
Q1:调低 keepalive_timeout 后正常用户会受影响吗?
微幅影响。keepalive_timeout从75秒降到15秒后,空闲连接更快释放,正常用户的连续请求会略微增加TCP握手开销。对于绝大多数Web应用(平均请求间隔小于5秒),影响极小。如果站点有大量静默长轮询,可将该值设置为30-45秒作为折衷。
Q2:iptables connlimit 限制30会不会误封公司NAT出口用户?
有可能。NAT环境下多个用户共享同一公网IP,30连接限制可能过严。建议将connlimit上限提高到50-80,同时配合limit_req(请求速率限制)做二次过滤。也可在Nginx日志中统计最大并发数后逐步调整。
总结
Slowloris慢速攻击防御的核心思路是缩短超时时间 + 限制连接数,从Nginx应用层和iptables网络层双管齐下。通过调低client_header_timeout/keepalive_timeout使不完整连接快速释放,结合connlimit限制单IP并发和Fail2ban自动封禁,形成完整防御闭环。建议将本配置与之前发布的Fail2ban防SSH爆破、Nginx limit_req CC防御方案组合使用,构建站点的全面防御体系。