Test wikitext: Difference between revisions
Blanked the page Tag: Blanking |
No edit summary |
||
| Line 1: | Line 1: | ||
== Linux 网站流量排查与最小防护框架 == | |||
网站突然变慢、无法访问,或者重启 Apache 后立刻恢复,往往说明问题不一定出在带宽本身,也可能是大量 TCP 连接占满了 Apache 的进程、线程或连接队列。 | |||
排查这类问题,不需要一次掌握所有网络工具。只要先建立一个最简单的认识:`ss` 用来观察连接,`ipset` 用来保存 IP 名单,`iptables` 用来决定放行或丢弃,`connlimit` 用来限制并发连接,`hashlimit` 用来限制建立新连接的速度。 | |||
=== ss:观察服务器当前的连接状态 === | |||
`ss` 是 Linux 中查看 Socket 状态的工具。它相当于服务器网络层的现场监控器。 | |||
网站打不开时,可以先查看 Apache 是否仍然在监听 HTTPS 端口: | |||
<syntaxhighlight lang="bash"> | |||
ss -lntp '( sport = :443 )' | |||
</syntaxhighlight> | |||
如果没有任何输出,说明当前没有程序监听 443 端口,问题应优先从 Apache 是否正常运行、HTTPS 配置是否成功加载等方向排查。 | |||
下面的命令可以统计当前已经建立的 HTTPS 连接数: | |||
<syntaxhighlight lang="bash"> | |||
ss -Hnt state established '( sport = :443 )' | wc -l | |||
</syntaxhighlight> | |||
`ESTABLISHED` 表示 TCP 三次握手已经完成。连接数量很高,不一定等于正在遭受攻击,也可能是正常访问、KeepAlive、爬虫或者慢连接,因此还需要观察来源 IP 和连接状态。 | |||
下面的命令统计尚未完成握手的 HTTPS 连接: | |||
<syntaxhighlight lang="bash"> | |||
ss -Hnt state syn-recv '( sport = :443 )' | wc -l | |||
</syntaxhighlight> | |||
如果 `SYN-RECV` 长时间异常增多,可能存在大量未完成的 TCP 握手,也可能与 SYN flood、网络丢包或服务器握手队列压力有关。 | |||
`watch` 可以让一条命令持续刷新。例如: | |||
<syntaxhighlight lang="bash"> | |||
watch -n 1 "ss -Hnt state established '( sport = :443 )' | wc -l" | |||
</syntaxhighlight> | |||
它表示每秒重新统计一次已经建立的 HTTPS 连接。 | |||
=== ipset:保存大量 IP 和网段 === | |||
`ipset` 是一个 IP 名单管理工具。它本身不决定封禁或放行,只负责保存 IP 地址和网段。 | |||
例如,`mw_white` 可以保存白名单,`mw_ban` 可以保存黑名单。iptables 只需要写一条规则,就能查询整个名单,不必为每个 IP 单独写一条防火墙规则。 | |||
可以把它理解成: | |||
'''ipset 是名单册,iptables 是门卫。''' | |||
向黑名单中加入一个 IP: | |||
<syntaxhighlight lang="bash"> | |||
ipset add mw_ban 74.7.227.12 | |||
</syntaxhighlight> | |||
向黑名单中加入整个 `/24` 网段: | |||
<syntaxhighlight lang="bash"> | |||
ipset add mw_ban 74.7.227.0/24 | |||
</syntaxhighlight> | |||
封禁 `/24` 网段时,通常会同时影响该网段中的最多 256 个 IPv4 地址,因此比封禁单个 IP 更容易误伤正常来源。 | |||
=== iptables:按照顺序检查流量 === | |||
iptables 会按照规则的先后顺序检查进入服务器的数据包。 | |||
一条规则可以检查来源 IP、目标端口、连接状态以及是否存在于某个 ipset 中,然后决定继续检查、返回上一层规则、接受或者丢弃。 | |||
`DROP` 表示静默丢弃数据包。`RETURN` 表示结束当前自定义链,返回调用它的上一层链继续检查。 | |||
iptables 中,`-I` 表示插入规则,`-A` 表示把规则追加到链尾。规则顺序非常重要,因为数据包匹配到 `DROP` 或 `ACCEPT` 后,通常不会继续检查后面的普通规则。 | |||
查看当前 INPUT 链及命中次数: | |||
<syntaxhighlight lang="bash"> | |||
iptables -L INPUT -n -v --line-numbers | |||
</syntaxhighlight> | |||
左侧的数据包数量会随着规则命中而增加,因此可以用来判断具体是哪一条规则正在发挥作用。 | |||
=== connlimit:限制一个 IP 同时占用的连接数 === | |||
`connlimit` 解决的是并发连接问题。 | |||
它关心的不是某个 IP 一天访问了多少次,而是某个 IP 此刻同时维持着多少条 TCP 连接。 | |||
如果一个来源 IP 同时保持几十甚至几百条连接,可能占用 Apache 的进程、线程和连接资源。connlimit 可以在该 IP 继续建立连接时直接丢弃新的连接。 | |||
它可以理解成: | |||
'''同一个人不能同时占用过多座位。''' | |||
=== hashlimit:限制一个 IP 建立新连接的速度 === | |||
`hashlimit` 解决的是新连接速率问题。 | |||
有些攻击不会长期保持大量连接,而是不断重复建立连接、关闭连接、再次建立连接。即使并发连接数不高,也可能持续消耗 TCP 握手、TLS 握手和 Apache 资源。 | |||
`hashlimit --hashlimit-mode srcip` 会为每个来源 IP 分别计算速度。 | |||
它可以理解成: | |||
'''同一个人不能在短时间内反复冲进大门。''' | |||
hashlimit 限制的是 TCP 新连接,不是 MediaWiki 页面请求次数。一个已经建立的 KeepAlive 连接可以继续发送多个 HTTP 请求,而不会重新进入 TCP 新连接状态。 | |||
因此,真正的 HTTP 请求洪水还需要 CDN、WAF、反向代理或 Apache 应用层规则处理。 | |||
=== 最小防护规则 === | |||
为了避免把测试规则散落在原有 INPUT 链中,可以单独建立一个自定义链: | |||
<syntaxhighlight lang="bash"> | |||
# 创建网站防护链;已经存在时忽略错误 | |||
iptables -N MW-WEB-GUARD 2>/dev/null || true | |||
# 清空网站防护链中的旧测试规则 | |||
iptables -F MW-WEB-GUARD </syntaxhighlight> | |||
白名单中的来源不受新增的并发和速率限制,但仍会返回原 INPUT 链,继续接受其他现有规则检查: | |||
<syntaxhighlight lang="bash"> | |||
# 白名单跳过本链中的网站连接限制 | |||
iptables -A MW-WEB-GUARD \ | |||
-m set --match-set mw_white src \ | |||
-j RETURN | |||
</syntaxhighlight> | |||
限制单个 IPv4 地址同时占用过多网站连接: | |||
<syntaxhighlight lang="bash"> | |||
# 单个 IPv4 地址同时超过 40 条网站连接时,拒绝继续建立新连接 | |||
iptables -A MW-WEB-GUARD \ | |||
-p tcp --syn \ | |||
-m connlimit \ | |||
--connlimit-above 40 \ | |||
--connlimit-mask 32 \ | |||
-j DROP | |||
</syntaxhighlight> | |||
这条规则限制的是同时存在的 TCP 连接数。它不会限制已经完成的 HTTP 请求总数。 | |||
限制单个 IPv4 地址持续高速建立新连接: | |||
<syntaxhighlight lang="bash"> | |||
# 单个 IPv4 地址持续超过每秒 10 个新连接时,丢弃超出的新连接 | |||
iptables -A MW-WEB-GUARD \ | |||
-p tcp --syn \ | |||
-m hashlimit \ | |||
--hashlimit-name mw_web_new \ | |||
--hashlimit-mode srcip \ | |||
--hashlimit-above 10/second \ | |||
--hashlimit-burst 30 \ | |||
--hashlimit-htable-expire 600000 \ | |||
-j DROP | |||
</syntaxhighlight> | |||
`10/second` 是长期允许的新连接平均速度,`burst 30` 用来容忍短时间的正常突发。该规则只丢弃超速期间的新连接,不会把来源 IP 永久加入黑名单。 | |||
让进入 80 和 443 端口的 TCP 流量经过自定义防护链: | |||
<syntaxhighlight lang="bash"> | |||
# 如果入口规则不存在,就把 80、443 流量送入网站防护链 | |||
iptables -C INPUT \ | |||
-p tcp \ | |||
-m multiport --dports 80,443 \ | |||
-j MW-WEB-GUARD 2>/dev/null || \ | |||
iptables -I INPUT 1 \ | |||
-p tcp \ | |||
-m multiport --dports 80,443 \ | |||
-j MW-WEB-GUARD | |||
</syntaxhighlight> | |||
`iptables -C` 用来检查规则是否已经存在。只有规则不存在时,后面的 `iptables -I` 才会执行,因此重复运行这段命令不会不断添加相同入口。 | |||
最终的流量路径是: | |||
网站流量先进入 `MW-WEB-GUARD`。白名单直接返回原 INPUT 链。其他来源先检查并发连接数,再检查建立新连接的速度。没有超限的流量返回 INPUT 链,继续经过服务器原有的腾讯云规则、黑名单规则和其他防火墙规则。 | |||
=== 查看规则是否命中 === | |||
查看自定义防护链: | |||
<syntaxhighlight lang="bash"> | |||
iptables -L MW-WEB-GUARD -n -v --line-numbers | |||
</syntaxhighlight> | |||
如果 connlimit 或 hashlimit 前面的数据包计数持续增加,说明对应规则正在丢弃超限连接。 | |||
查看 INPUT 链中的入口: | |||
<syntaxhighlight lang="bash"> | |||
iptables -L INPUT -n -v --line-numbers | |||
</syntaxhighlight> | |||
INPUT 链中应当只有一条指向 `MW-WEB-GUARD` 的 80、443 端口入口。 | |||
=== 撤销自定义防护链 === | |||
删除 INPUT 链中的入口: | |||
<syntaxhighlight lang="bash"> | |||
iptables -D INPUT \ | |||
-p tcp \ | |||
-m multiport --dports 80,443 \ | |||
-j MW-WEB-GUARD | |||
</syntaxhighlight> | |||
清空并删除自定义链: | |||
<syntaxhighlight lang="bash"> | |||
iptables -F MW-WEB-GUARD | |||
iptables -X MW-WEB-GUARD | |||
</syntaxhighlight> | |||
由于所有新增限制都集中在自定义链中,删除入口和自定义链即可撤销这套规则,不会修改 `mw_white`、`mw_ban`、腾讯云规则或 SSH 规则。 | |||
=== Apache 与防火墙的边界 === | |||
iptables 工作在 Apache 外部。它能根据 IP、端口、TCP 状态和连接速率丢弃流量,但看不懂具体的 MediaWiki 页面和 HTTP 请求内容。 | |||
Apache 负责处理已经进入服务器的 HTTP 请求。慢速发送请求头、慢速上传请求体、KeepAlive 长时间空闲,以及 Apache worker 被占满,都属于 Apache 层的问题。 | |||
`KeepAliveTimeout` 控制持久连接完成请求后可以空闲等待多久。较短的等待时间可以减少空闲连接长期占用资源。 | |||
`RequestReadTimeout` 控制客户端必须在多长时间内、以多快的速度发送完请求头或请求体,它主要用于处理慢速 HTTP 请求。 | |||
Apache 的 `event MPM` 能比 `prefork MPM` 更有效地处理大量空闲 KeepAlive 连接,但它是否适合当前服务器,还取决于 PHP 使用的是 mod_php 还是 PHP-FPM。 | |||
防火墙和 Apache 的关系可以概括为: | |||
'''iptables 负责控制谁能建立连接,Apache 负责控制连接进入以后怎样处理请求。''' | |||
=== 最终概念 === | |||
`ss` 用来观察连接现场。 | |||
`ipset` 用来保存 IP 和网段名单。 | |||
`iptables` 用来按照顺序决定流量的去向。 | |||
`connlimit` 用来限制单个 IP 同时占用的连接数。 | |||
`hashlimit` 用来限制单个 IP 建立新连接的速度。 | |||
Apache 负责处理已经进入服务器的 HTTP 请求。 | |||
CDN、WAF 和云厂商负责处理服务器上游的分布式攻击、带宽型攻击和应用层请求洪水。 | |||
最小防护结构只需要保留三件事:已确认的恶意来源进入 `mw_ban`,单 IP 并发过高由 connlimit 处理,单 IP 建立连接过快由 hashlimit 处理。 | |||
规则并不是越多越安全。每一条规则都应当明确统计的对象,以及正常流量可能在什么情况下被误伤。 | |||
Revision as of 23:22, 13 July 2026
Linux 网站流量排查与最小防护框架
网站突然变慢、无法访问,或者重启 Apache 后立刻恢复,往往说明问题不一定出在带宽本身,也可能是大量 TCP 连接占满了 Apache 的进程、线程或连接队列。
排查这类问题,不需要一次掌握所有网络工具。只要先建立一个最简单的认识:`ss` 用来观察连接,`ipset` 用来保存 IP 名单,`iptables` 用来决定放行或丢弃,`connlimit` 用来限制并发连接,`hashlimit` 用来限制建立新连接的速度。
ss:观察服务器当前的连接状态
`ss` 是 Linux 中查看 Socket 状态的工具。它相当于服务器网络层的现场监控器。
网站打不开时,可以先查看 Apache 是否仍然在监听 HTTPS 端口:
ss -lntp '( sport = :443 )'
如果没有任何输出,说明当前没有程序监听 443 端口,问题应优先从 Apache 是否正常运行、HTTPS 配置是否成功加载等方向排查。
下面的命令可以统计当前已经建立的 HTTPS 连接数:
ss -Hnt state established '( sport = :443 )' | wc -l
`ESTABLISHED` 表示 TCP 三次握手已经完成。连接数量很高,不一定等于正在遭受攻击,也可能是正常访问、KeepAlive、爬虫或者慢连接,因此还需要观察来源 IP 和连接状态。
下面的命令统计尚未完成握手的 HTTPS 连接:
ss -Hnt state syn-recv '( sport = :443 )' | wc -l
如果 `SYN-RECV` 长时间异常增多,可能存在大量未完成的 TCP 握手,也可能与 SYN flood、网络丢包或服务器握手队列压力有关。
`watch` 可以让一条命令持续刷新。例如:
watch -n 1 "ss -Hnt state established '( sport = :443 )' | wc -l"
它表示每秒重新统计一次已经建立的 HTTPS 连接。
ipset:保存大量 IP 和网段
`ipset` 是一个 IP 名单管理工具。它本身不决定封禁或放行,只负责保存 IP 地址和网段。
例如,`mw_white` 可以保存白名单,`mw_ban` 可以保存黑名单。iptables 只需要写一条规则,就能查询整个名单,不必为每个 IP 单独写一条防火墙规则。
可以把它理解成:
ipset 是名单册,iptables 是门卫。
向黑名单中加入一个 IP:
ipset add mw_ban 74.7.227.12
向黑名单中加入整个 `/24` 网段:
ipset add mw_ban 74.7.227.0/24
封禁 `/24` 网段时,通常会同时影响该网段中的最多 256 个 IPv4 地址,因此比封禁单个 IP 更容易误伤正常来源。
iptables:按照顺序检查流量
iptables 会按照规则的先后顺序检查进入服务器的数据包。
一条规则可以检查来源 IP、目标端口、连接状态以及是否存在于某个 ipset 中,然后决定继续检查、返回上一层规则、接受或者丢弃。
`DROP` 表示静默丢弃数据包。`RETURN` 表示结束当前自定义链,返回调用它的上一层链继续检查。
iptables 中,`-I` 表示插入规则,`-A` 表示把规则追加到链尾。规则顺序非常重要,因为数据包匹配到 `DROP` 或 `ACCEPT` 后,通常不会继续检查后面的普通规则。
查看当前 INPUT 链及命中次数:
iptables -L INPUT -n -v --line-numbers
左侧的数据包数量会随着规则命中而增加,因此可以用来判断具体是哪一条规则正在发挥作用。
connlimit:限制一个 IP 同时占用的连接数
`connlimit` 解决的是并发连接问题。
它关心的不是某个 IP 一天访问了多少次,而是某个 IP 此刻同时维持着多少条 TCP 连接。
如果一个来源 IP 同时保持几十甚至几百条连接,可能占用 Apache 的进程、线程和连接资源。connlimit 可以在该 IP 继续建立连接时直接丢弃新的连接。
它可以理解成:
同一个人不能同时占用过多座位。
hashlimit:限制一个 IP 建立新连接的速度
`hashlimit` 解决的是新连接速率问题。
有些攻击不会长期保持大量连接,而是不断重复建立连接、关闭连接、再次建立连接。即使并发连接数不高,也可能持续消耗 TCP 握手、TLS 握手和 Apache 资源。
`hashlimit --hashlimit-mode srcip` 会为每个来源 IP 分别计算速度。
它可以理解成:
同一个人不能在短时间内反复冲进大门。
hashlimit 限制的是 TCP 新连接,不是 MediaWiki 页面请求次数。一个已经建立的 KeepAlive 连接可以继续发送多个 HTTP 请求,而不会重新进入 TCP 新连接状态。
因此,真正的 HTTP 请求洪水还需要 CDN、WAF、反向代理或 Apache 应用层规则处理。
最小防护规则
为了避免把测试规则散落在原有 INPUT 链中,可以单独建立一个自定义链:
# 创建网站防护链;已经存在时忽略错误
iptables -N MW-WEB-GUARD 2>/dev/null || true
# 清空网站防护链中的旧测试规则
iptables -F MW-WEB-GUARD
白名单中的来源不受新增的并发和速率限制,但仍会返回原 INPUT 链,继续接受其他现有规则检查:
# 白名单跳过本链中的网站连接限制
iptables -A MW-WEB-GUARD \
-m set --match-set mw_white src \
-j RETURN
限制单个 IPv4 地址同时占用过多网站连接:
# 单个 IPv4 地址同时超过 40 条网站连接时,拒绝继续建立新连接
iptables -A MW-WEB-GUARD \
-p tcp --syn \
-m connlimit \
--connlimit-above 40 \
--connlimit-mask 32 \
-j DROP
这条规则限制的是同时存在的 TCP 连接数。它不会限制已经完成的 HTTP 请求总数。
限制单个 IPv4 地址持续高速建立新连接:
# 单个 IPv4 地址持续超过每秒 10 个新连接时,丢弃超出的新连接
iptables -A MW-WEB-GUARD \
-p tcp --syn \
-m hashlimit \
--hashlimit-name mw_web_new \
--hashlimit-mode srcip \
--hashlimit-above 10/second \
--hashlimit-burst 30 \
--hashlimit-htable-expire 600000 \
-j DROP
`10/second` 是长期允许的新连接平均速度,`burst 30` 用来容忍短时间的正常突发。该规则只丢弃超速期间的新连接,不会把来源 IP 永久加入黑名单。
让进入 80 和 443 端口的 TCP 流量经过自定义防护链:
# 如果入口规则不存在,就把 80、443 流量送入网站防护链
iptables -C INPUT \
-p tcp \
-m multiport --dports 80,443 \
-j MW-WEB-GUARD 2>/dev/null || \
iptables -I INPUT 1 \
-p tcp \
-m multiport --dports 80,443 \
-j MW-WEB-GUARD
`iptables -C` 用来检查规则是否已经存在。只有规则不存在时,后面的 `iptables -I` 才会执行,因此重复运行这段命令不会不断添加相同入口。
最终的流量路径是:
网站流量先进入 `MW-WEB-GUARD`。白名单直接返回原 INPUT 链。其他来源先检查并发连接数,再检查建立新连接的速度。没有超限的流量返回 INPUT 链,继续经过服务器原有的腾讯云规则、黑名单规则和其他防火墙规则。
查看规则是否命中
查看自定义防护链:
iptables -L MW-WEB-GUARD -n -v --line-numbers
如果 connlimit 或 hashlimit 前面的数据包计数持续增加,说明对应规则正在丢弃超限连接。
查看 INPUT 链中的入口:
iptables -L INPUT -n -v --line-numbers
INPUT 链中应当只有一条指向 `MW-WEB-GUARD` 的 80、443 端口入口。
撤销自定义防护链
删除 INPUT 链中的入口:
iptables -D INPUT \
-p tcp \
-m multiport --dports 80,443 \
-j MW-WEB-GUARD
清空并删除自定义链:
iptables -F MW-WEB-GUARD
iptables -X MW-WEB-GUARD
由于所有新增限制都集中在自定义链中,删除入口和自定义链即可撤销这套规则,不会修改 `mw_white`、`mw_ban`、腾讯云规则或 SSH 规则。
Apache 与防火墙的边界
iptables 工作在 Apache 外部。它能根据 IP、端口、TCP 状态和连接速率丢弃流量,但看不懂具体的 MediaWiki 页面和 HTTP 请求内容。
Apache 负责处理已经进入服务器的 HTTP 请求。慢速发送请求头、慢速上传请求体、KeepAlive 长时间空闲,以及 Apache worker 被占满,都属于 Apache 层的问题。
`KeepAliveTimeout` 控制持久连接完成请求后可以空闲等待多久。较短的等待时间可以减少空闲连接长期占用资源。
`RequestReadTimeout` 控制客户端必须在多长时间内、以多快的速度发送完请求头或请求体,它主要用于处理慢速 HTTP 请求。
Apache 的 `event MPM` 能比 `prefork MPM` 更有效地处理大量空闲 KeepAlive 连接,但它是否适合当前服务器,还取决于 PHP 使用的是 mod_php 还是 PHP-FPM。
防火墙和 Apache 的关系可以概括为:
iptables 负责控制谁能建立连接,Apache 负责控制连接进入以后怎样处理请求。
最终概念
`ss` 用来观察连接现场。
`ipset` 用来保存 IP 和网段名单。
`iptables` 用来按照顺序决定流量的去向。
`connlimit` 用来限制单个 IP 同时占用的连接数。
`hashlimit` 用来限制单个 IP 建立新连接的速度。
Apache 负责处理已经进入服务器的 HTTP 请求。
CDN、WAF 和云厂商负责处理服务器上游的分布式攻击、带宽型攻击和应用层请求洪水。
最小防护结构只需要保留三件事:已确认的恶意来源进入 `mw_ban`,单 IP 并发过高由 connlimit 处理,单 IP 建立连接过快由 hashlimit 处理。
规则并不是越多越安全。每一条规则都应当明确统计的对象,以及正常流量可能在什么情况下被误伤。