跑网站迟早会遇到 DDoS 攻击。小站可能只是被扫一下就过去了,但要是真被盯上,几分钟就能把服务器打瘫。这篇文章整理了 6 种防御思路和应急处理办法,都是从实际经历里总结的。

先搞清楚 DDoS 是怎么回事

DDoS(分布式拒绝服务)说白了就是用大量请求把你的服务器带宽或资源耗尽,让正常用户访问不了。常见的有三类:

  • 流量型:直接用 UDP、ICMP 洪水把带宽塞满,小水管服务器特别容易中招
  • 协议型:利用 TCP 三次握手的缺陷,发大量 SYN 包但不完成连接,耗尽服务器连接数
  • 应用层:模拟正常用户发 HTTP 请求,比如疯狂刷某个数据库查询很重的页面,这种最难防

大多数小站遇到的是前两种,用 Cloudflare 免费版就能扛住。第三种需要更细的策略。

怎么判断自己被打了

服务器突然变慢或者完全打不开,先别急着重启,看看是不是被攻击了:

# 看当前连接数,正常小站一般不超过几百
netstat -an | wc -l

# 看 SYN_RECV 状态的连接,如果几千个就不对劲了
netstat -an | grep SYN_RECV | wc -l

# 看哪些 IP 连接最多
netstat -ntu | awk '{print $5}' | cut -d: -f1 | sort | uniq -c | sort -rn | head -20

# 用 iftop 看实时流量(需要先装)
sudo apt install iftop -y && sudo iftop -n

如果某个 IP 有几百上千个连接,或者入站流量远超平时,基本可以确认了。

6 种防御方法

1. 接入 Cloudflare(最简单)

对大多数小站来说,把域名 DNS 切到 Cloudflare 就行了。免费版能防住大部分流量型和协议型攻击。设置也简单:

  • 注册 Cloudflare,添加域名,按提示改 NS 记录
  • SSL 模式选 Full(Strict),前提是源站有证书
  • 开启"Under Attack Mode"可以在被打时临时启用,会给访客一个 5 秒验证页

注意一点:接了 Cloudflare 之后,源站 IP 不要泄露。检查一下 DNS 历史记录、邮件头、API 接口有没有暴露真实 IP。

2. 内核参数调优

调整 Linux 内核参数能提高服务器对 SYN Flood 的抵抗力:

# 编辑 /etc/sysctl.conf,加入以下内容
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_max_syn_backlog = 65535
net.ipv4.tcp_synack_retries = 2
net.ipv4.tcp_syn_retries = 2
net.ipv4.tcp_fin_timeout = 15
net.ipv4.tcp_keepalive_time = 300
net.ipv4.tcp_tw_reuse = 1
net.core.somaxconn = 65535
net.core.netdev_max_backlog = 65535

# 生效
sudo sysctl -p

其中 tcp_syncookies 最关键,开启后内核在 SYN 队列满时会用 cookie 验证连接,不会直接拒绝。

3. 用 iptables/nftables 做限流

针对单 IP 连接数和请求频率做限制:

# 限制单 IP 每秒新建连接不超过 20 个
iptables -A INPUT -p tcp --syn -m connlimit --connlimit-above 20 -j DROP

# 限制单 IP 每秒请求数
iptables -A INPUT -p tcp --dport 80 -m state --state NEW -m recent --set
iptables -A INPUT -p tcp --dport 80 -m state --state NEW -m recent --update --seconds 1 --hitcount 20 -j DROP

# 丢弃明显的扫描包
iptables -A INPUT -p tcp --tcp-flags ALL NONE -j DROP
iptables -A INPUT -p tcp --tcp-flags ALL ALL -j DROP

被打的时候如果能确定攻击源 IP 段,直接封掉最快:

# 封一个 IP
iptables -A INPUT -s 1.2.3.4 -j DROP

# 封一个 C 段
iptables -A INPUT -s 1.2.3.0/24 -j DROP

4. Nginx 层面的防护

如果用 Nginx 做反向代理,可以加限流配置:

# 在 http 块中定义限流区
limit_req_zone $binary_remote_addr zone=req_limit:10m rate=10r/s;
limit_conn_zone $binary_remote_addr zone=conn_limit:10m;

# 在 server 块中使用
server {
    limit_req zone=req_limit burst=20 nodelay;
    limit_conn conn_limit 10;

    # 屏蔽没有 User-Agent 的请求(很多攻击工具不带)
    if ($http_user_agent = "") {
        return 444;
    }
}

444 是 Nginx 特有的状态码,直接断开连接不返回任何内容,比返回 403 省资源。

5. Fail2Ban 自动封禁

Fail2Ban 可以自动分析日志,把异常 IP 加入防火墙黑名单:

sudo apt install fail2ban -y

创建配置文件 /etc/fail2ban/jail.local

[nginx-limit-req]
enabled = true
filter = nginx-limit-req
action = iptables-multiport[name=nginx-limit-req, port="80,443"]
logpath = /var/log/nginx/error.log
findtime = 60
maxretry = 10
bantime = 3600

这样 Nginx 限流触发后,对应 IP 会被自动封禁一小时。

6. 换 IP 或者上高防

如果攻击直接打 IP 而不是域名,而且流量超过服务器带宽(比如几十 G),上面那些方法都没用。这时候要么:

  • 联系云厂商换一个 IP,然后不要暴露新 IP
  • 买高防 IP 或高防 CDN,阿里云、腾讯云都有,按月或按量计费
  • 临时把站停了等攻击停——说起来窝囊,但有时候最实际

被打的时候应急处理

真被打了别慌,按这个顺序来:

  1. 先确认是 DDoS 还是自己代码有 bug 导致的高负载
  2. 开启 Cloudflare 的 Under Attack Mode(如果接了的话)
  3. SSH 登录服务器看连接状况,找出攻击特征(IP 段、请求路径、User-Agent)
  4. 用 iptables 封掉攻击源,或者直接在宝塔面板的防火墙里加规则
  5. 如果带宽已经被打满连 SSH 都上不去,联系云厂商客服,他们可以在上游帮你过滤

几个容易忽略的点

  • 宝塔面板自带的防火墙(Nginx 防火墙插件)其实挺好用的,能做 CC 防护和 IP 黑名单,先用起来
  • 定期检查有没有泄露源站 IP:用 SecurityTrails 或者 dig 命令查历史 DNS 记录
  • 数据库查询慢的页面容易被应用层攻击利用,给这些页面加缓存
  • 攻击结束后记得把临时加的 iptables 规则清理掉,别把正常用户也封了

DDoS 防御没有一劳永逸的方案,但对于大多数小站来说,Cloudflare 免费版加上基本的内核和 Nginx 调优就足够了。真被大流量打了,花钱上高防是最直接的办法。