Skip to content

⚡ DDoS 防护 ​

DDoS(Distributed Denial of Service)攻击的目标不是入侵服务器,而是用海量流量把它"淹死"——CPU 打满、带宽塞满、连接表耗尽,正常用户完全无法访问。

DDoS 类型一览 ​

类型原理攻击目标难度
SYN Flood发送大量 TCP SYN 包但不完成握手,耗尽连接队列服务器 TCP 栈★★☆
UDP Flood发送海量 UDP 包,占满带宽网络带宽★☆☆
HTTP Flood(CC)大量合法的 HTTP 请求,消耗应用层资源Web 应用(CPU/内存)★★★
Slowloris建立连接后极慢地发送请求头,占满连接池Web 服务器连接池★★★
DNS Amplification伪造源 IP 向 DNS 发送小请求,DNS 返回大响应打到目标网络带宽★★☆
NTP Amplification类似 DNS 放大,利用 NTP monlist 漏洞网络带宽★☆☆

放大攻击

DNS Amplification 和 NTP Amplification 的"放大倍数"可达 50-200 倍——攻击者发送 1Mbps 请求,目标收到 200Mbps 垃圾数据。这种攻击依赖网络中开放的 DNS/NTP 服务器作为"反射器"。

Nginx 限流:防 CC 攻击 ​

CC 攻击(Challenge Collapsar)是应用层 DDoS,用大量看似正常的 HTTP 请求消耗服务器资源。

请求频率限制(limit_req) ​

在 nginx.conf 的 http 块中定义:

nginx
http {
    # 定义一个限流区域:binary_remote_addr 为键,每秒 10 个请求,突发 20
    limit_req_zone $binary_remote_addr zone=perip:10m rate=10r/s;

    # 针对特定路径更严格的限制
    limit_req_zone $binary_remote_addr zone=login:10m rate=3r/m;

    server {
        # 对全站应用
        limit_req zone=perip burst=20 nodelay;

        # 登录接口更严格:每分钟 3 次,突发 5
        location /login {
            limit_req zone=login burst=5 nodelay;
        }
    }
}

参数说明:

  • rate=10r/s:每秒 10 个请求
  • burst=20:允许额外 20 个突发请求排队等待
  • nodelay:突发请求不排队,立即处理(不设则排队等待)

并发连接限制(limit_conn) ​

nginx
http {
    # 每个 IP 最多 10 个并发连接
    limit_conn_zone $binary_remote_addr zone=perconn:10m;

    # 按 server_name 限制总连接
    limit_conn_zone $server_name zone=perserver:10m;

    server {
        limit_conn perconn 10;
        limit_conn perserver 500;
    }
}

完整防 CC 配置模板 ​

nginx
http {
    # === 基础调优 ===
    # 减少 keepalive 时间
    keepalive_timeout 15;
    keepalive_requests 100;

    # 关闭慢客户端
    client_body_timeout 10;
    client_header_timeout 10;
    send_timeout 10;

    # body 大小限制
    client_max_body_size 10m;
    client_body_buffer_size 128k;

    # === 限流区域 ===
    # 全局:每秒 30 请求,突发 50
    limit_req_zone $binary_remote_addr zone=global:10m rate=30r/s;

    # API:每秒 10 请求,突发 20
    limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;

    # 静态文件:每秒 100 请求
    limit_req_zone $binary_remote_addr zone=static:10m rate=100r/s;

    # IP 并发限制
    limit_conn_zone $binary_remote_addr zone=connperip:10m;

    server {
        limit_req zone=global burst=50 nodelay;
        limit_conn connperip 20;

        location / {
            try_files $uri $uri/ =404;
        }

        location /api/ {
            limit_req zone=api burst=20 nodelay;
            proxy_pass http://backend;
        }

        location ~* \.(jpg|jpeg|png|gif|css|js|woff2)$ {
            limit_req zone=static burst=200 nodelay;
            expires 7d;
            add_header Cache-Control "public, immutable";
        }

        # 拒绝空 User-Agent 和常见扫描器
        if ($http_user_agent ~* (scrapy|curl|wget|python|nikto|sqlmap|nmap)) {
            return 444;
        }
    }
}

iptables 限制连接频率 ​

在 Nginx 之前,iptables 可以做第一层过滤:

bash
# === 限制每个 IP 的新连接速率 ===
# 每秒最多 5 个新的 TCP 连接
iptables -A INPUT -p tcp -m state --state NEW \
    -m hashlimit \
    --hashlimit-name conn_rate \
    --hashlimit-above 5/sec \
    --hashlimit-burst 10 \
    --hashlimit-mode srcip \
    -j DROP

# === 限制每个 IP 的并发连接 ===
# HTTP/HTTPS 每个 IP 最多 50 个并发
iptables -A INPUT -p tcp --dport 80 \
    -m connlimit --connlimit-above 50 --connlimit-mask 32 \
    -j DROP

iptables -A INPUT -p tcp --dport 443 \
    -m connlimit --connlimit-above 50 --connlimit-mask 32 \
    -j DROP

# === 限制 SSH 并发连接 ===
iptables -A INPUT -p tcp --dport 22 \
    -m connlimit --connlimit-above 5 --connlimit-mask 32 \
    -j DROP

sysctl 防 SYN Flood 参数 ​

config
# /etc/sysctl.d/99-ddos.conf

# SYN Cookie:队列满时用 cookie 验证
net.ipv4.tcp_syncookies = 1

# 增大 SYN 队列
net.ipv4.tcp_max_syn_backlog = 65536

# SYN+ACK 重试次数(默认 5,调低减少半开连接)
net.ipv4.tcp_synack_retries = 1

# SYN 包重传次数
net.ipv4.tcp_syn_retries = 2

# 缩短 TIME_WAIT 回收
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_fin_timeout = 15

# 增大连接追踪表(防装满)
net.netfilter.nf_conntrack_max = 2097152
net.netfilter.nf_conntrack_tcp_timeout_established = 1200
net.netfilter.nf_conntrack_tcp_timeout_syn_recv = 30
net.netfilter.nf_conntrack_tcp_timeout_syn_sent = 30
net.netfilter.nf_conntrack_tcp_timeout_time_wait = 5

# 快速回收孤儿 socket
net.ipv4.tcp_max_orphans = 65536

# 开启 TCP fastopen(服务端/客户端)
net.ipv4.tcp_fastopen = 3

# 防止 TIME_WAIT 泛洪
net.ipv4.tcp_max_tw_buckets = 1440000
bash
sudo sysctl -p /etc/sysctl.d/99-ddos.conf

CDN 缓解:Cloudflare ​

对于大规模 DDoS(几百 Gbps 级别),单台服务器无论怎么调参都没用——带宽早就打满了。这时候必须有 CDN 在前面"挡刀"。

Cloudflare 免费版就提供基础 DDoS 保护:

  1. DNS 托管:把域名的 NS 记录指向 Cloudflare
  2. 代理模式:Cloudflare 的 CDN 节点承接所有流量,只转发合法请求到源站
  3. 源站隐藏:Cloudflare 的 IP 暴露在公网,你的服务器真实 IP 不暴露
  4. WAF 规则:可配置速率限制、IP 封禁、挑战验证

源站 IP 泄露

如果攻击者知道了你的源站真实 IP,他们可以直接绕过 Cloudflare 攻击你的服务器。泄露途径包括:邮件头中的源站 IP、DNS 历史记录、直接访问源站 IP 的 Web 服务。确保源站只接受来自 Cloudflare IP 段的请求,或者配置防火墙白名单。

bash
# 源站 iptables 只允许 Cloudflare IP(需要定期更新)
# Cloudflare IP 列表:https://www.cloudflare.com/ips/
sudo ufw allow from 173.245.48.0/20 to any port 443
sudo ufw allow from 103.21.244.0/22 to any port 443
# ... (完整列表请从 Cloudflare 获取)
sudo ufw deny 443

检测当前是否在遭受攻击 ​

bash
# 查看每个 IP 的连接数,发现异常高者
ss -tan | awk '{print $1}' | cut -d: -f1 | sort | uniq -c | sort -rn | head -20

# netstat 版本
netstat -ntu | awk '{print $5}' | cut -d: -f1 | sort | uniq -c | sort -nr | head -20

# 查看 SYN_RECV 状态连接数(SYN Flood 特征)
ss -tan state syn-recv | wc -l

# 实时查看 nginx 请求频率
tail -f /var/log/nginx/access.log | awk '{print $1}' | uniq -c

# 带宽监控
nload
iftop

🧪 练习题 ​

  1. 用 ab(Apache Bench)或 wrk 对你的 Nginx 发起 1000 并发请求,验证 limit_req 是否生效
  2. 尝试用 hping3 模拟 SYN Flood(仅在本地虚拟机测试!),观察 tcp_syncookies 的效果
  3. 配置 Cloudflare 代理你的域名,用 iptables 限制源站只接受 Cloudflare 的请求

DDoS 打的是"量",更难对付的是已经渗透进来的攻击者——应急响应。


🎯 本章要点 ​

  • CC 攻击是应用层 DDoS,请求本身合法,但海量请求耗尽服务器 CPU/内存。
  • limit_req 基于令牌桶算法限制请求速率(如每秒 10 个请求),超限返回 503。
加载练习题中...