Test wikitext

From 清冽之泉
Revision as of 23:06, 13 July 2026 by Mwroot (talk | contribs) (Created page with "== 总框架 == 排查网站被骚扰、连接占满或访问困难时,应当先区分五个层级: {| class="wikitable" ! 层级 ! 观察对象 ! 主要工具 | ! 解决的问题 | | ------------------------------------ | | 上游网络 | | 总带宽、分布式 DDoS | | 云厂商、CDN、WAF | | 流量是否已经在到达服务器之前堵塞线路...")
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

总框架

排查网站被骚扰、连接占满或访问困难时,应当先区分五个层级:

层级 观察对象 主要工具

整体路径可以记成:

Internet ↓ 云厂商/CDN/WAF ↓ iptables+ipset ↓ Linux TCP Socket ↓ Apache worker/thread ↓ MediaWiki+PHP+MariaDB

ipset 和 iptables 只能看见 IP、端口、数据包和连接状态;它们看不懂“这个人一秒钟请求了多少个 MediaWiki 页面”。

原笔记中最需要纠正的地方

1. estab 662 不等于 443 端口有 662 条连接

ss -s

`ss -s` 中:

estab 662

表示这台服务器当前共有大约 662 个处于 `ESTABLISHED` 状态的 TCP Socket,可能包括:

  • Apache 的 80、443;
  • SSH 的 22;
  • MariaDB、代理、邮件等其他连接;
  • 本机主动连接到外界的连接。

它只是全局概览,不是 Apache 专用统计。`ss -s` 的 `-s` 是 `--summary`,意思是输出 Socket 汇总统计。

精确查看服务器本地 443 端口的已建立连接,应使用:

ss -Hnt state established '( sport = :443 )'

只统计数量:

ss -Hnt state established '( sport = :443 )' | wc -l

这里的参数含义:

参数 英文

`ss` 支持直接按 TCP 状态及 `sport`、`dport` 过滤,所以比用 `grep :443` 更精确。

2. netstat 加 grep 只能粗略计数

原命令:

netstat -ant | grep :443 | wc -l

参数含义:

参数 英文

痛点在于,含有 `:443` 的行可能包括:

  • 本地端口是 443;
  • 对方端口碰巧是 443;
  • `ESTABLISHED`;
  • `TIME_WAIT`;
  • `SYN_RECV`;
  • `FIN_WAIT`;
  • 监听 Socket。

所以它只能回答:

“当前 Socket 列表中,有多少行出现了 :443?”

不能直接回答:

“当前有多少个已经建立的 HTTPS 入站连接?”

而且 `netstat` 已被其手册列为基本过时,官方建议使用 `ss` 替代。

因此这条命令可以从核心笔记中删除,统一使用 `ss`。

ss:排查 TCP Socket 的主力工具

`ss` 可以理解为 `Socket Statistics`。它解决的核心痛点是:

“网站访问异常时,连接究竟处于什么状态?”

查看全局概况

ss -s

用途:

  • 快速确认系统 Socket 总数是否突然异常;
  • 判断 `ESTABLISHED`、`TIME-WAIT` 等是否非常多;
  • 适合第一眼查看,不适合精确归因。

查看 443 的各种状态分别有多少

ss -Hnt '( sport = :443 )' |
awk '{print $1}' |
sort |
uniq -c |
sort -nr

可能输出:

ESTAB 500 TIME-WAIT 300 SYN-RECV 80 CLOSE-WAIT 20

各状态的大致含义:

状态 含义

`ss` 支持 `established`、`syn-recv`、`time-wait`、`close-wait` 等标准 TCP 状态。

只看已经建立的 HTTPS 连接

ss -Hnt state established '( sport = :443 )' | wc -l

这条命令解决:

“现在究竟有多少条连接已经真正进入 HTTPS 服务?”

监控变化:

watch -n 1 \
"ss -Hnt state established '( sport = :443 )' | wc -l"

`watch -n 1`:

  • `watch`:重复执行命令;
  • `-n`:`interval`,刷新间隔;
  • `1`:每一秒执行一次。

查看半连接数量

ss -Hnt state syn-recv '( sport = :443 )' | wc -l

这条命令解决:

“现在是否有大量 TCP 握手没有完成?”

如果 `SYN-RECV` 持续很多,而 `ESTABLISHED` 不一定很多,更接近:

  • SYN flood;
  • 对方大量发 SYN 后不完成握手;
  • 线路丢包;
  • 服务器握手队列或网络栈压力。

找出连接最多的来源 IP

推荐写法:

ss -Hnt state established '( sport = :443 )' |
awk '{print $5}' |
sed -E 's/^\[?([^]]+)\]?:[0-9]+$/\1/' |
sort |
uniq -c |
sort -nr |
head

作用:

1. `ss` 找出本地 443 的已建立连接; 2. `awk '{print $5}'` 取出对方地址和端口; 3. `sed` 去掉对方端口; 4. `sort` 排序; 5. `uniq -c` 合并相同 IP,并统计出现次数; 6. `sort -nr` 按数字倒序; 7. `head` 显示前十名。

各命令的英文概念:

命令 英文概念

原来的命令:

ss -ant | awk '{print $5}' | cut -d: -f1 |
sort | uniq -c | sort -nr | head

主要有三个问题:

  • 没有限定本地 443;
  • 没有限定 `ESTABLISHED`;
  • `cut -d: -f1` 遇到 IPv6 地址会被冒号切坏。

确认 Apache 是否还在监听 443

ss -lntp '( sport = :443 )'

参数:

  • `-l`:`--listening`,只看监听 Socket;
  • `-p`:`--processes`,显示占用 Socket 的进程。

这条命令解决:

“Apache 究竟还在不在 443 端口上听连接?”

如果完全没有输出,可能是:

  • Apache 已经停止;
  • TLS 虚拟主机没有成功加载;
  • 443 被其他程序占用;
  • Apache 启动失败。

攻击和资源耗尽的范畴

不要把所有“网站打不开”都叫作同一种攻击。

范畴 攻击或异常方式 主要观察

尤其要记住:

`connlimit` 管“同时有多少条连接”。

`hashlimit` 管“单位时间来了多少个匹配的数据包或新连接”。

iptables 不负责统计“HTTP 页面请求次数”。

在 HTTP/1.1 KeepAlive、HTTP/2 等情况下,同一条 TCP 连接可以承载多次请求,所以限制 TCP `NEW` 只能缓解连接洪水,不能完整阻止 HTTP flood。

ipset:维护大批量 IP 名单

ipset 解决的痛点是:

“如果有几百、几千、几万个恶意 IP,不能为每个 IP 写一条 iptables 规则。”

iptables 只需要写一条规则,去查询 ipset 名单。

创建可保存 IP 和网段的黑名单

ipset create banhash hash:net \
  family inet \
  hashsize 4096 \
  maxelem 65536

各部分含义:

参数 英文

`hash:net` 可以同时保存:

74.7.227.12 74.7.227.0/24 10.0.0.0/8

它适合保存大小不一的网段。

如果脚本可能被重复运行,可以使用:

ipset create banhash hash:net \
  family inet \
  hashsize 4096 \
  maxelem 65536 \
  -exist

`-exist` 的作用是:集合已经存在时,不把它当作错误。

添加单个 IP

ipset add banhash 74.7.227.12

添加整个 /24 网段

ipset add banhash 74.7.227.0/24

`/24` 表示前 24 位是网络部分,通常覆盖:

74.7.227.0 ~ 74.7.227.255

这不是“封一个 IP”,而是封整个网段。

必须确认该网段确实大量恶意,避免误伤同一网段内的正常用户、搜索引擎、代理或云服务。

让 iptables 使用该黑名单

iptables -I INPUT \
  -m set \
  --match-set banhash src \
  -j DROP

该规则解决的需求是:

“只要来源地址存在于 banhash,就在进入 Apache 以前直接丢弃。”

参数含义:

参数 英文

iptables 的规则按顺序检查;`-I` 默认插到链首,`-A` 则追加到链尾。匹配到 `ACCEPT` 或 `DROP` 后,就不会再继续检查后面的普通规则。

因此不能机械地认为“插到第一条永远最好”。

例如已有:

  • 管理员白名单;
  • 腾讯云安全链;
  • SSH 防锁死规则;
  • 其他必要的 ACCEPT 规则;

就要先设计清楚顺序。

查看现有顺序:

iptables -L INPUT -n -v --line-numbers

正确统计 ipset 中的成员数量

原命令:

ipset list banhash | wc -l

统计的是输出总行数,其中还包含:

  • Name;
  • Type;
  • Revision;
  • Header;
  • Members;
  • 其他说明行。

它不是准确的成员数。

更合适的写法:

ipset save banhash | grep -c '^add banhash '

动态监控:

watch -n 1 \
"ipset save banhash | grep -c '^add banhash '"

connlimit:限制单个 IP 的并发连接数

推荐按“建立连接时”检查:

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

该规则解决的痛点是:

“同一个来源 IP 同时维持大量 HTTPS 连接,占满 Apache 或服务器连接资源。”

各部分含义:

参数 英文

connlimit 官方定义就是按客户端 IP 或客户端地址块限制并行连接数量;IPv4 未指定 mask 时默认也是最完整的主机前缀,即按单 IP,但显式写 `32` 更容易理解。

需要注意:

  • 它限制的是 TCP 并发连接,不是 HTTP 请求;
  • 公司、学校、移动网络可能有许多正常用户共享同一个公网 IP;
  • 若服务器位于 CDN 或反向代理之后,服务器可能只看见 CDN 节点 IP;
  • 阈值 20、30 并不是通用真理,应根据正常访问峰值确定。

所以:

`--connlimit-above 30`

比较准确的解释是:

“如果这个来源 IP 当前已经拥有超过 30 条被 conntrack 统计的并行连接,则匹配并丢弃新的 SYN。”

不能简单理解为“任何时候都绝对只允许 30 个用户”。

hashlimit:按 IP 限制新连接速率

原笔记中的这类规则,方向是正确的:

iptables -I INPUT \
  -p tcp \
  --dport 443 \
  -m conntrack \
  --ctstate NEW \
  -m hashlimit \
  --hashlimit-name HTTPS \
  --hashlimit-above 30/minute \
  --hashlimit-burst 20 \
  --hashlimit-mode srcip \
  --hashlimit-htable-expire 600000 \
  -j DROP

它解决的痛点是:

“某个来源 IP 不维持大量长连接,而是不断快速建立新连接。”

参数解释

参数 英文

hashlimit 可以按来源 IP、来源端口、目标 IP、目标端口分别建立速率桶;`srcip` 才是“每个来源 IP 各算各的”。

令牌桶的直观理解

可以把每个 IP 想象成有一个水桶:

  • `--hashlimit-burst 20`:桶最多暂存 20 个令牌;
  • 正常速率会不断补充令牌;
  • 新连接消耗令牌;
  • 短时间突然来几次,可以使用桶里积攒的令牌;
  • 长期超过平均速率,桶会耗尽,后续包便匹配 `--hashlimit-above`。

因此 burst 不是:

“超过 20 就永久封禁。”

而是:

“允许短时间突发,但不允许长期持续超速。”

30/minute 可能过于严格

`30/minute` 等于平均每两秒一个新连接。

现代网页可能同时加载:

  • HTML;
  • CSS;
  • JavaScript;
  • 图片;
  • API;
  • 字体;
  • 多个域名资源。

虽然 KeepAlive 会减少新连接,但移动网络重连、共享 NAT、爬虫和浏览器并发仍可能触发较低阈值。

所以 `30/minute` 更适合作为一个需要验证的实验参数,而不是默认安全值。

应先观察正常峰值,再确定:

  • 每秒还是每分钟;
  • 平均速率;
  • burst;
  • 是否按单 IP、网段或全局统计。

NEW 不等于 HTTP 请求

conntrack 中:

  • `NEW`:连接尚未看到双向数据,或者刚开始建立;
  • `ESTABLISHED`:连接已经看到双向数据。

所以:

`--ctstate NEW`

限制的是新 TCP 连接相关的数据包,不是:

GET /wiki/Page POST /api.php GET /load.php

一个 `ESTABLISHED` TCP KeepAlive 连接,可以继续发送很多 HTTP 请求,而不会再次进入 `NEW`。

因此原笔记里的:

NEW limit → 防 HTTP flood

应改为:

NEW/SYN rate limit → 防新连接洪水、短连接洪水

真正按 HTTP URL 或请求次数限速,应在:

  • CDN;
  • WAF;
  • 反向代理;
  • Apache 模块;
  • 应用层;

完成。

limit:全局限速,不是单 IP 限速

原规则:

iptables -I INPUT \
  -p tcp \
  --dport 443 \
  -m conntrack \
  --ctstate NEW \
  -m limit \
  --limit 30/second \
  --limit-burst 60 \
  -j ACCEPT

iptables -A INPUT 
-p tcp 
--dport 443 
-m conntrack 
--ctstate NEW 
-j DROP

它表达的不是:

“每个 IP 每秒最多 30 个新连接。”

而是:

“整个服务器的这条规则,所有来源 IP 加起来,平均每秒允许 30 个匹配包,突发最多 60;其余新连接全部丢弃。”

`limit` 使用的是单个共享令牌桶。官方将它定义为按有限平均速率进行匹配;`hashlimit` 才能按来源 IP 等维度分组。

这类规则的痛点是:

“服务器过载时,无论是谁都不再接受超过全局上限的新连接。”

它属于全局熔断器,而不是精细反滥用规则。

风险包括:

  • 所有正常用户共用同一个额度;
  • 攻击者可以消耗掉正常用户的额度;
  • `ACCEPT` 会立即终止当前链的普通检查,可能绕过后续规则;
  • `-I` 和 `-A` 混用后,实际顺序容易与想象不同;
  • 如果现有 INPUT 链还有其他规则,盲目追加最终 DROP 很危险。

所以这组规则不应作为日常核心规则,建议从主笔记中删除,只保留其概念:

limit = 全局速率桶

hashlimit = 可按来源 IP 分组的速率桶

SYN limit:限制整个服务器的握手速率

原规则:

iptables -I INPUT \
  -p tcp \
  --syn \
  --dport 443 \
  -m limit \
  --limit 50/second \
  --limit-burst 100 \
  -j ACCEPT

iptables -A INPUT 
-p tcp 
--syn 
--dport 443 
-j DROP

它解决的需求是:

“整个服务器每秒最多接收一定数量的 TCP 建连 SYN,超出的全部丢弃。”

注意:

  • 它是全局限制;
  • 不区分正常 IP 和攻击 IP;
  • 它与全局 `NEW limit` 高度重复;
  • SYN flood 若已经占满服务器外部带宽,本机 iptables 再丢包也无法疏通上游线路;
  • 分布式攻击需要云厂商、CDN、WAF 或上游清洗。

因此不建议同时堆叠:

  • 全局 SYN limit;
  • 全局 NEW limit;
  • per-IP hashlimit;
  • recent hitcount;

否则自己很难知道究竟是哪条规则造成误伤。

日常基础防护中,更容易理解的组合是:

  1. 已知坏 IP:ipset
  1. 单 IP 并发:connlimit
  1. 单 IP 新连接速率:hashlimit

全局 SYN 限速只作为经过正常流量基线验证后的额外熔断方案。

recent:滚动记录最近命中的 IP

原规则:

iptables -I INPUT \
  -p tcp \
  --dport 443 \
  -m recent \
  --set

iptables -I INPUT 
-p tcp 
--dport 443 
-m recent 
--update 
--seconds 1 
--hitcount 20 
-j DROP

`recent` 模块解决的痛点是:

“动态记住最近出现过的来源 IP,并按最近若干秒内的命中次数进行判断。”

参数:

参数 英文

recent 可以维护动态 IP 列表,并结合 `seconds`、`hitcount` 判断最近时间窗口内的命中次数。

但原规则有两个严重的理解问题。

第一,它没有写:

--syn

也没有写:

--ctstate NEW

所以它可能记录的是到达 443 的 TCP 数据包,而不是“HTTP 访问次数”或“新连接次数”。

正常传输一个网页,本身就会产生许多 TCP 包,很容易超过 20。

第二,连续使用 `-I` 时,后执行的规则会插到前面。命令书写顺序和最终规则顺序正好相反,维护起来很容易迷糊。

这类需求已经可以由:

hashlimit --hashlimit-mode srcip

更直观地解决。

因此建议把 recent 从核心防护笔记中删除。等将来明确需要“动态记名单”而不仅是“丢弃超速包”时,再单独研究。

去除重复后,iptables 防护只保留三类概念

第一层:已知黑名单

解决:

“这个 IP 或网段已经确认恶意,不必再给它机会。”

-m set --match-set banhash src -j DROP

核心工具:

ipset

第二层:单 IP 并发限制

解决:

“一个 IP 同时占着太多连接不放。”

-p tcp --syn --dport 443 \
-m connlimit \
--connlimit-above N \
--connlimit-mask 32 \
-j DROP

核心工具:

connlimit

`N` 必须根据正常流量确定。

第三层:单 IP 新连接速率限制

解决:

“一个 IP 不保持连接,而是不断创建短连接。”

-p tcp --syn --dport 443 \
-m hashlimit \
--hashlimit-name HTTPS_NEW \
--hashlimit-mode srcip \
--hashlimit-above R/second \
--hashlimit-burst B \
--hashlimit-htable-expire 600000 \
-j DROP

核心工具:

hashlimit

`R` 是平均速率,`B` 是允许的瞬时突发。

暂时从核心规则中删除

  • 全局 `limit ACCEPT` 加最终 `DROP`;
  • 全局 SYN limit;
  • 全局 NEW limit;
  • recent hitcount。

不是因为这些模块完全无用,而是因为它们:

  • 与现有规则重复;
  • 更容易误伤;
  • 依赖准确的流量基线;
  • 增加规则顺序的理解难度。

Apache 层:iptables 无法解决的资源耗尽

重启 Apache 后立刻恢复说明什么

这种现象比较符合:

  • Apache worker 或 thread 被占满;
  • 大量连接被 Apache 进程持有;
  • 某些进程卡住;
  • 请求队列积压;
  • 重启后旧连接和进程状态被清空。

但它不是绝对证明。

要结合以下信息判断:

ss -Hnt state established '( sport = :443 )' | wc -l
ss -Hnt state syn-recv '( sport = :443 )' | wc -l
apache2ctl -M | grep mpm
systemctl status apache2

KeepAlive 不是应该关闭的坏东西

KeepAlive 的作用是:

“让一个 TCP 连接承载多个 HTTP 请求,避免每张图片、每个脚本都重新握手和重新进行 TLS。”

Apache 默认:

KeepAlive On KeepAliveTimeout 5 MaxKeepAliveRequests 100

较高的 `KeepAliveTimeout` 会让更多服务器进程或线程等待空闲客户端;Apache 官方也建议遭遇 DoS 风险时适当降低该值。

较保守的起点可以是:

KeepAlive On
KeepAliveTimeout 2
MaxKeepAliveRequests 100

其中:

  • `KeepAlive On`:保留正常性能优势;
  • `KeepAliveTimeout 2`:空闲两秒后关闭持久连接;
  • `MaxKeepAliveRequests 100`:每条持久连接最多处理 100 个请求。

原笔记建议:

MaxKeepAliveRequests 50

不一定比 100 更安全。

Apache 官方反而建议该值保持较高,以取得较好的性能;设置过低会增加 TCP 和 TLS 重新建连次数。

所以核心防护重点应放在:

KeepAliveTimeout

而不是盲目压低:

MaxKeepAliveRequests

慢速发送请求应由 RequestReadTimeout 处理

慢连接攻击不一定是“连接后保持空闲”,也可能是:

  • 每隔几秒发送一个 HTTP 头字符;
  • 很慢地上传请求体;
  • 让 Apache 一直等待一个永远发不完的请求。

这类问题应由 Apache 的:

RequestReadTimeout

限制客户端发送请求头和请求体的时间及最低速率。Apache 官方将其列为缓解 DoS 的重要指令。

Apache MPM 比单纯 KeepAlive 更重要

查看当前 MPM:

apache2ctl -M | grep mpm

可能看到:

mpm_prefork_module mpm_worker_module mpm_event_module

概念区别:

MPM 模型

Apache 官方说明,event MPM 使用异步方式处理部分连接工作,避免每条空闲连接长期占用一个工作线程。

MaxRequestWorkers 是 Apache 的总容量

`MaxRequestWorkers` 决定 Apache 同时允许多少请求进入处理状态。

它过低:

  • 正常峰值也容易排队;
  • 攻击者更容易占满。

它过高:

  • 可能耗尽内存;
  • PHP、数据库也可能被拖垮。

Apache 官方建议根据服务器资源调整它,使服务器能够处理足够并发,又不至于耗尽资源。

压力测试工具

压力测试解决的痛点是:

“规则和 Apache 配置修改后,服务器在可控负载下究竟会发生什么?”

只能对自己拥有或明确获准测试的服务器进行。

ab:固定请求总数和并发数

安装:

apt install apache2-utils

测试:

ab -n 5000 -c 200 https://qingliezhiquan.com/

参数:

参数 英文

Apache 官方将 ab 定义为 HTTP 服务器基准测试工具,用于观察服务器每秒能够处理多少请求。

特别注意:

ab 默认不开启 HTTP KeepAlive。

所以:

ab -n 5000 -c 200 https://qingliezhiquan.com/

更偏向测试不断发请求和建立连接的情况。

测试 KeepAlive:

ab -k -n 5000 -c 200 https://qingliezhiquan.com/

`-k` 在 ab 中表示:

keep alive

即复用 HTTP 连接。

wrk:持续一段时间维持大量连接

安装:

apt install wrk

测试:

wrk -t8 -c200 -d30s https://qingliezhiquan.com/

参数:

参数 英文

wrk 的官方说明中,`connections` 是测试期间保持打开的总 HTTP 连接数,连接会分配给各测试线程。

它比 ab 更适合观察:

  • 持续吞吐量;
  • 延迟;
  • 大量连接长期存在时的表现;
  • Apache KeepAlive 和 worker 压力。

curl 循环:粗略制造一批独立请求

for i in {1..100}; do
  curl -k https://qingliezhiquan.com/ &
done
wait

作用:

  • 创建 100 个后台 curl 进程;
  • 每个进程请求一次;
  • `&` 放入后台;
  • `wait` 等待所有后台进程结束。

需要纠正:

curl 的 `-k` 不是 KeepAlive。

它表示:

--insecure

即不验证 HTTPS 证书。

所以这只是一个粗糙的并发冒烟测试,不是精确压力测试,也不能准确模拟慢连接攻击。

如何判断防护是否有效

不能只看:

failed requests connection reset

因为这些现象也可能意味着规则过于严格,误伤了正常请求。

应同时观察:

watch -n 1 \
"ss -Hnt state established '( sport = :443 )' | wc -l"
watch -n 1 \
"ss -Hnt state syn-recv '( sport = :443 )' | wc -l"
iptables -L INPUT -n -v --line-numbers

以及:

  • 网站是否仍可正常打开;
  • 正常请求延迟是否上升;
  • Apache 是否仍有可用 worker;
  • CPU、内存是否耗尽;
  • iptables 对应规则的包计数是否增长;
  • 是否出现大量正常用户误伤。

真正的目标是:

“在恶意或异常负载出现时,服务器仍能为正常用户保留服务能力。”

不是单纯追求:

“压力测试出现越多失败越好。”

网站异常时的排查顺序

第一步:确认服务是否还在监听

ss -lntp '( sport = :443 )'

没有监听,先排查 Apache。

第二步:查看全局 Socket 概况

ss -s

确认是否有异常数量的 Socket。

第三步:按状态拆分 443 连接

ss -Hnt '( sport = :443 )' |
awk '{print $1}' |
sort |
uniq -c |
sort -nr

重点区分:

  • `ESTABLISHED` 很多;
  • `SYN-RECV` 很多;
  • `TIME-WAIT` 很多;
  • `CLOSE-WAIT` 很多。

第四步:找连接最多的来源 IP

ss -Hnt state established '( sport = :443 )' |
awk '{print $5}' |
sed -E 's/^\[?([^]]+)\]?:[0-9]+$/\1/' |
sort |
uniq -c |
sort -nr |
head

第五步:查看防火墙规则是否正在命中

iptables -L INPUT -n -v --line-numbers

重点看:

  • 每条规则前的 packets;
  • bytes;
  • DROP 规则是否快速增长;
  • 规则顺序是否符合设计。

第六步:查看 ipset 名单

ipset list banhash
ipset save banhash | grep -c '^add banhash '

第七步:根据现象选择防线

现象

最终记忆模型

ipset = 名单管理员 = 保存哪些 IP 或网段属于白名单、黑名单

iptables = 门卫 = 根据名单、端口、连接状态决定放行或丢弃

connlimit = 数一个 IP 现在同时占着多少条连接

hashlimit = 数一个 IP 最近建立连接有多快

limit = 数所有人加起来有多快

recent = 记录最近出现过的 IP 和命中次数,但容易与 hashlimit 重复

ss = 查看服务器当前实际存在什么 Socket、处于什么 TCP 状态

Apache = TCP 连接进门以后,负责读取和处理 HTTP 请求

CDN/WAF = 在服务器上游识别和阻挡分布式攻击及 HTTP 层攻击

最精简、最容易维护的防护框架是:

1. ipset 黑名单:处理已经确认的恶意来源 2. connlimit:处理单 IP 并发连接占满 3. hashlimit:处理单 IP 新连接洪水 4. Apache 超时与 event MPM:处理慢请求和空闲持久连接 5. CDN/WAF/云厂商:处理 HTTP flood 和分布式 DDoS

不要为了“防得更多”而把所有模块都叠上去。

防火墙规则越多,越需要明确回答两个问题:

这条规则到底统计什么? 超过阈值后究竟会误伤谁?