Slowloris慢速攻击防御实战:Nginx与iptables多层防护配置

适用场景

本文面向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.confhttp 块,配置以下关键参数:

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防御方案组合使用,构建站点的全面防御体系。