四层DDoS和七层DDoS有什么区别?防护怎么选

站长圈里说「被 DDoS 了」,其实包含两种完全不同的攻击:四层 DDoS(L4,传输层)七层 DDoS(L7,应用层)。前者拼的是流量和连接数,后者拼的是请求数,判定依据、防护位置、误伤风险全都不一样。本文用 9 个问答讲清两者的区别、怎么从现象上判断自己被打的是哪一层,以及高防 IP、CDN、WAF、Nginx、iptables 在分层防护里的分工,配置均可直接复制。

Q:四层 DDoS 和七层 DDoS 分别指什么?

四层是传输层,攻击对象是 TCP/UDP 连接本身,攻击者不需要和你的业务逻辑打交道,只要能建立连接就能消耗资源。典型形态有 SYN Flood、UDP Flood、ACK Flood、ICMP Flood、连接耗尽型攻击。

七层是应用层,攻击对象是 HTTP/HTTPS 请求,服务器必须把请求解析到 Host、URL、Header 才能响应,所以攻击者发来的每一个请求都会消耗你的 CPU、PHP 进程和数据库连接。典型形态有 HTTP Flood、CC 攻击、慢速攻击(Slowloris、慢速 POST)、爬虫式高频请求。

一句话概括:四层看「连接」,七层看「请求内容」

Q:两者最核心的区别是什么?

可以从五个维度对比。

  • 判定依据:四层只看源 IP、目的 IP、端口和标志位;七层要解析 Host、URL、Header、Cookie 才能判断是不是恶意。
  • 攻击成本:四层拼的是真实流量,需要带宽,成本高;七层只需要请求,一个请求几百字节,几十元就能打出几万 QPS。
  • 防护位置:四层可以在运营商侧、清洗中心、服务器内核和 iptables 上防;七层必须在能解开 TLS 的代理层(CDN、WAF、Nginx)才能防。
  • 误伤风险:四层策略粗,做封段容易误伤;七层策略细,但如果没有白名单,也会把正常用户一起挑战。
  • 被攻击时的表现:四层被打,网卡和带宽先满,服务器可能连 SSH 都登不上;七层被打,带宽看着不高,CPU 和 PHP 进程却已经跑满。

Q:怎么从现象上判断被打的是哪一层?

先看带宽和连接数,再看 CPU 和请求日志,两条命令基本就能定性。

# 1. 连接数总览:SYN_RECV 大量堆积 → 偏四层
ss -s
netstat -an | awk '{print $6}' | sort | uniq -c | sort -rn

# 2. 日志里的请求分布:单 IP、单 URL 高度集中 → 偏七层
awk '{print $1}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -10
awk '{print $7}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -10

判断标准很直接:带宽打满、conntrack 表接近上限、SSH 连不上,是四层;带宽正常、CPU 100%、日志里某个 URL 被反复请求,是七层。两者也可能同时发生,那就按「先四层后七层」的顺序处理。

Q:四层攻击怎么防?先做哪几件事?

四层攻击的本质是资源和容量问题,单机配置只能抬门槛,真正兜底要靠上游清洗。

  • 把自己藏起来:接入高防 IP 或云清洗,域名解析到防护地址,源站只放行防护节点回源;源站 IP 一旦泄露,一切都白搭。
  • 内核参数收紧:SYN Cookie、半连接队列、conntrack 上限是必调项。
  • 单 IP 新建连接限速:在 iptables 层拦掉明显异常的连接频率。
# /etc/sysctl.d/99-anti-ddos.conf
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_max_syn_backlog = 65535
net.ipv4.tcp_synack_retries = 2
net.ipv4.tcp_fin_timeout = 15
net.netfilter.nf_conntrack_max = 1048576
net.netfilter.nf_conntrack_tcp_timeout_syn_recv = 20
# 生效:sysctl -p /etc/sysctl.d/99-anti-ddos.conf
# 单 IP 新建连接超过 20/s 直接丢弃
iptables -N SYN_FLOOD
iptables -A INPUT -p tcp --syn -j SYN_FLOOD
iptables -A SYN_FLOOD -m limit --limit 20/s --limit-burst 40 -j RETURN
iptables -A SYN_FLOOD -j DROP

注意 --limit-burst 不要设太小,否则正常用户的一次页面加载(会并发建多个连接)也会被丢掉。

Q:七层攻击怎么防?Nginx 该怎么配?

七层防护的核心是按路径和来源做差异化限速,而不是给整站套一条统一的规则。

# http 块中定义限速区
limit_req_zone $binary_remote_addr zone=perip:20m rate=10r/s;
limit_conn_zone $binary_remote_addr zone=connperip:10m;
limit_req_status 429;
limit_conn_status 429;

# 动态接口单独用一个更严的区
limit_req_zone $binary_remote_addr zone=api:10m rate=3r/s;

location ~ ^/(search|api|comment) {
    limit_req zone=api burst=6 nodelay;
    limit_conn connperip 10;
    proxy_pass http://backend;
}

location / {
    limit_req zone=perip burst=20 nodelay;
    limit_conn connperip 30;
    proxy_pass http://backend;
}
  • 静态资源不要走限速 zone,让它们命中缓存,限速只用来保护动态路径。
  • burst 和 nodelay 一起用:burst 决定瞬时允许的突发数,nodelay 表示突发请求立即处理而不是排队,避免正常用户感到卡顿。
  • 超过阈值返回 429 而不是 503,429 的语义更准确,也方便在日志里单独统计拦截量。

Q:为什么说防护要「四层先过一遍、七层再过一遍」?

因为两层防护解决的问题不同,缺一层都会被穿透。

  • 只有四层防护:高防 IP 清洗的是流量和连接异常,但 CC 的每个请求都是「合法连接 + 合法请求头」,照样完整穿透到源站,CPU 依然被打满。
  • 只有七层防护:连接数被四层攻击打满时,WAF 自身回源建连也会被拖死,规则再准也执行不下去。
  • 正确顺序:云清洗(L4,识别并丢弃异常连接)→ CDN/WAF(L7,解开 TLS 后按语义识别)→ 源站 Nginx 限速与缓存(最后兜底)。

验证方法:攻击时同时看源站带宽和 CPU。带宽明显下降但 CPU 没降,说明攻击就在七层,需要补的是 WAF 规则和限速,而不是继续加防护带宽。

Q:只买高防 IP、不配 WAF 行不行?

对四层攻击可以,对七层攻击不行。高防 IP 的清洗逻辑主要基于流量特征、连接频率、包大小分布,它没有能力判断「同一个 IP 用正常速度请求搜索页 5000 次」是不是恶意。

选购时看两个指标就够:是否支持七层防护规则(CC 规则、频率限制、人机验证),以及清洗能力是否按连接数计费。只按带宽计费的高防,面对 CC 时基本不起作用。

Q:CDN 在分层防护里扮演什么角色?

CDN 天然就是一个分布式的七层代理层:它解开 TLS、能按 URL 和 Header 下发规则、能缓存静态内容、还能隐藏源站 IP。所以 CDN 更擅长挡七层高频请求和爬虫,超大流量的四层攻击还是要靠高防和清洗

接入 CDN 后必须配好真实 IP 还原,否则限速会把 CDN 节点当成同一个客户端,一次把整个节点封掉。

# 每一段 CDN 回源 IP 都写成一行,禁止写 0.0.0.0/0
set_real_ip_from 1.2.3.0/24;
set_real_ip_from 1.2.4.0/24;
real_ip_header X-Forwarded-For;
real_ip_recursive on;

# 回源侧对单节点限速,防止某个节点被刷时把源站拖垮
limit_req_zone $binary_remote_addr zone=cdnnode:10m rate=200r/s;

Q:还有什么补充建议?

  • 先测再防:平时用压测记录基线(正常带宽、QPS、CPU、连接数、缓存命中率),攻击时才有对照,否则只能凭感觉判断。
  • 日志要能分层看:源站日志建议区分「清洗后的流量」和「直连流量」,最好加一个记录真实来源 IP 的字段,方便事后回溯。
  • 源站 IP 保护是前提:历史 DNS 记录、网站证书透明度日志、邮件头、第三方扫描都会泄露源站 IP,换过 IP 之后也要检查老记录。
  • 应急顺序别搞反:先切高防(四层)→ 再开 CDN 缓存和 WAF 规则(七层)→ 临时上人机验证 → 最后才考虑封 IP 段。反过来做,最容易先误伤自己的用户。