服务器安全防护总论: Difference between revisions
No edit summary |
|||
| (One intermediate revision by the same user not shown) | |||
| Line 185: | Line 185: | ||
流量进入 <code>MW-WEB-GUARD</code> 后,白名单会先返回原 INPUT 链。其他来源依次检查并发连接数和建立新连接的速度。没有超限的流量走到自定义链末尾时,也会自动返回 INPUT 链,继续经过原有的腾讯云规则、黑名单规则和其他防火墙规则。 | 流量进入 <code>MW-WEB-GUARD</code> 后,白名单会先返回原 INPUT 链。其他来源依次检查并发连接数和建立新连接的速度。没有超限的流量走到自定义链末尾时,也会自动返回 INPUT 链,继续经过原有的腾讯云规则、黑名单规则和其他防火墙规则。 | ||
这套命令使用的是 IPv4 的 <code>iptables<code>。如果服务器同时通过 IPv6 对外提供网站服务,IPv6 流量需要由 <code>ip6tables</code>、nftables 或相应的 IPv6 防火墙规则处理。 | 这套命令使用的是 IPv4 的 <code>iptables</code>。如果服务器同时通过 IPv6 对外提供网站服务,IPv6 流量需要由 <code>ip6tables</code>、nftables 或相应的 IPv6 防火墙规则处理。 | ||
== 查看命中与撤销规则 == | == 查看命中与撤销规则 == | ||
| Line 273: | Line 273: | ||
CDN、WAF 和云厂商负责在服务器上游处理分布式攻击、带宽型攻击和应用层请求洪水。 | CDN、WAF 和云厂商负责在服务器上游处理分布式攻击、带宽型攻击和应用层请求洪水。 | ||
最小防护结构只需要保留三个核心方向:已经确认的恶意来源进入 <code>mw_ban<code>,单 IP 并发连接过高由 connlimit 处理,单 IP 建立新连接过快由 hashlimit 处理。 | 最小防护结构只需要保留三个核心方向:已经确认的恶意来源进入 <code>mw_ban</code>,单 IP 并发连接过高由 connlimit 处理,单 IP 建立新连接过快由 hashlimit 处理。 | ||
'''防火墙规则的价值不在于数量,而在于每条规则都明确知道自己限制的对象。''' | '''防火墙规则的价值不在于数量,而在于每条规则都明确知道自己限制的对象。''' | ||
Latest revision as of 00:23, 14 July 2026
网站突然变慢、无法访问,或者重启 Apache 后立即恢复,可能不是带宽已经耗尽,而是大量 TCP 连接占用了 Apache 的进程、线程或连接队列。排查这类问题时,只需先建立一个简单框架:ss 负责观察连接,ipset 负责保存 IP 名单,iptables 负责决定放行或丢弃,connlimit 限制一个 IP 同时占用的连接数,hashlimit 限制一个 IP 建立新连接的速度。
观察连接现场:ss 与 watch
ss 是 Linux 中查看 Socket 状态的工具,可以把它理解成服务器网络层的现场监控器。它能够显示服务器是否仍在监听端口、目前有多少连接,以及这些连接处在 TCP 通信的哪个阶段。
下面的命令显示整个系统的 Socket 概况:
ss -s
它适合快速判断服务器的连接总量是否突然异常,但不能直接说明 443 端口有多少连接。
下面的命令检查是否仍有程序监听 HTTPS 端口:
ss -lntp '( sport = :443 )'
如果没有任何输出,说明当前没有程序监听 443 端口。问题通常应从 Apache 是否运行、HTTPS 配置是否成功加载、端口是否被其他程序占用等方向排查。
下面的命令统计已经完成 TCP 握手的 HTTPS 连接:
ss -Hnt state established '( sport = :443 )' | wc -l
ESTABLISHED 表示 TCP 三次握手已经完成。这些连接可能来自正常用户、搜索引擎、爬虫、KeepAlive 或慢连接,因此连接数量很高并不自动等于正在遭受攻击。
下面的命令统计尚未完成握手的 HTTPS 连接:
ss -Hnt state syn-recv '( sport = :443 )' | wc -l
如果 SYN-RECV 长时间异常增多,说明服务器收到了大量连接请求,但其中许多握手没有完成。这可能与 SYN flood、网络丢包或者 TCP 握手队列压力有关。
watch 本身不懂网络,它只是反复执行另一条命令。例如:
watch -n 1 "ss -Hnt state established '( sport = :443 )' | wc -l"
这表示每秒重新统计一次已经建立的 HTTPS 连接。
ss 负责观察,watch 负责持续观察。
管理名单与检查流量:ipset 和 iptables
ipset 是一个 IP 名单管理工具。它可以保存单个 IP,也可以保存整个网段。它本身不决定放行还是封禁,只负责维护名单。
例如,mw_white 可以保存白名单,mw_ban 可以保存黑名单。iptables 只需使用一条规则,便能查询整个名单,不必为每个 IP 分别建立一条防火墙规则。
向黑名单加入一个 IP:
ipset add mw_ban 74.7.227.12
向黑名单加入整个 /24 网段:
ipset add mw_ban 74.7.227.0/24
一个 /24 网段通常包含最多 256 个 IPv4 地址。封禁整个网段能够一次处理大量同源地址,但也比封禁单个 IP 更容易影响同一网段中的正常来源。
iptables 是真正执行网络判断的工具。进入服务器的数据包会按照规则的先后顺序接受检查。规则可以检查来源地址、目标端口、连接状态和 ipset 名单,然后决定继续检查、接受、返回上一层规则或者直接丢弃。
DROP 表示静默丢弃数据包。RETURN 表示结束当前自定义链,返回调用它的上一层链继续检查。
-I 是插入规则,-A 是把规则追加到链尾。由于 iptables 从上到下检查规则,规则顺序会直接影响最终结果。
下面的命令可以查看 INPUT 链、规则编号和每条规则的命中次数:
iptables -L INPUT -n -v --line-numbers
规则左侧的数据包数量会随着命中而增加,因此可以据此判断具体是哪条规则正在发挥作用。
ipset 是名单册,iptables 是按照名单和条件执行判断的门卫。
两种核心限制:connlimit 和 hashlimit
connlimit 解决的是并发连接问题。它关心的不是某个 IP 一天访问了多少次,而是这个 IP 此刻同时保持着多少条 TCP 连接。
如果一个来源 IP 同时保持几十甚至几百条连接,它可能持续占用服务器的 Socket、Apache 进程或工作线程。connlimit 可以在连接数量超过阈值以后,拒绝这个来源继续建立新连接。
connlimit 限制的是一个 IP 同时占用多少个座位。
hashlimit 解决的是新连接速度问题。有些异常流量不会长期保持大量连接,而是不断重复建立连接、关闭连接、再次建立连接。即使同时存在的连接数量不高,这种行为仍然会反复消耗 TCP 握手、TLS 握手和 Apache 资源。
使用 --hashlimit-mode srcip 时,每个来源 IP 都会单独计算速度。某个 IP 超过速率,只会影响这个 IP,不会让所有访问者共同争抢一个总额度。
hashlimit 限制的是一个 IP 冲进大门的速度。
hashlimit 看到的是 TCP 新连接,而不是 MediaWiki 页面请求。一个已经建立的 KeepAlive 连接可以连续发送多个 HTTP 请求,不会因为每次请求页面而重新进入 TCP 新连接状态。
因此,connlimit 和 hashlimit 主要处理连接层面的异常。真正的 HTTP 请求洪水还需要 CDN、WAF、反向代理或者 Apache 应用层规则处理。
最小防护规则
为了避免把新增规则散落在原有 INPUT 链中,可以建立一条独立的自定义链。所有网站连接限制都集中放在这条链里,撤销时也只需要删除这一条入口和自定义链。
应用规则前,可以把当前状态保存为文本备份:
# 保存当前 iptables 规则
iptables-save > /root/iptables-before-web-guard.v4
# 保存当前 ipset 名单
ipset save > /root/ipset-before-web-guard.set
建立独立的网站防护链:
# 如果防护链不存在,就创建它
iptables -nL MW-WEB-GUARD >/dev/null 2>&1 || \
iptables -N MW-WEB-GUARD
# 清空防护链中的旧测试规则
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-saddr \
--connlimit-above 40 \
--connlimit-mask 32 \
-j DROP
这条规则只在对方建立新连接时检查。--connlimit-saddr 表示按照来源地址统计,--connlimit-mask 32 表示每个 IPv4 地址单独计算。
限制单个 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 用来检查入口规则是否已经存在。只有规则不存在时,后面的插入命令才会执行,因此重复运行不会不断产生相同入口。
流量进入 MW-WEB-GUARD 后,白名单会先返回原 INPUT 链。其他来源依次检查并发连接数和建立新连接的速度。没有超限的流量走到自定义链末尾时,也会自动返回 INPUT 链,继续经过原有的腾讯云规则、黑名单规则和其他防火墙规则。
这套命令使用的是 IPv4 的 iptables。如果服务器同时通过 IPv6 对外提供网站服务,IPv6 流量需要由 ip6tables、nftables 或相应的 IPv6 防火墙规则处理。
查看命中与撤销规则
下面的命令显示自定义防护链及其命中次数:
iptables -L MW-WEB-GUARD -n -v --line-numbers
如果 connlimit 或 hashlimit 规则前面的数据包计数持续增加,说明相应规则正在丢弃超限的新连接。
下面的命令显示 INPUT 链中的入口:
iptables -L INPUT -n -v --line-numbers
INPUT 链中应当存在一条把 80、443 端口流量送入 MW-WEB-GUARD 的规则。
压力测试可以使用 Apache 自带的 ab 工具。例如:
ab -n 500 -c 50 https://qingliezhiquan.com/
这表示总共发送 500 个请求,同时保持最多 50 个并发请求。由于 ab 默认会频繁建立新连接,它可能同时触发 connlimit 和 hashlimit。
如果压力测试的来源 IP 存在于 mw_white 中,该来源会跳过本链限制,因此不会验证这两条规则。
撤销规则时,先删除 INPUT 链中的入口:
# 删除 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、腾讯云链或其他原有规则。
也可以使用备份完整恢复此前的 iptables 状态:
iptables-restore < /root/iptables-before-web-guard.v4
Apache 与防火墙的边界
iptables 工作在 Apache 外部。它可以根据 IP、端口、TCP 标志、连接数量和连接速度丢弃流量,但它看不懂具体访问的是哪个 MediaWiki 页面,也不知道一个已经建立的连接中发送了多少次 HTTP 请求。
Apache 负责处理已经进入服务器的 HTTP 请求。慢速发送请求头、慢速上传请求体、KeepAlive 长时间空闲以及 Apache 工作线程被占满,都属于 Apache 层的问题。
KeepAliveTimeout 控制一次请求完成后,持久连接还可以空闲等待多久。等待时间较短,可以减少空闲连接长期占用服务器资源。
RequestReadTimeout 控制客户端必须在多长时间内、以怎样的最低速度发送完请求头或请求体。它主要用来处理故意极慢发送数据的 HTTP 客户端。
Apache 的 event MPM 比 prefork MPM 更擅长处理大量空闲 KeepAlive 连接,因为它不必让主要工作线程一直等待空闲连接。但 MPM 的选择还与 PHP 使用的是 mod_php 还是 PHP-FPM 有关。
iptables 负责控制谁能建立连接,Apache 负责控制连接进入以后怎样处理请求。
最终概念
ss 用来观察服务器当前存在什么连接,以及这些连接处于什么 TCP 状态。
ipset 用来保存 IP 和网段名单。
iptables 用来按照规则顺序决定流量的去向。
connlimit 用来限制单个 IP 同时占用的连接数量。
hashlimit 用来限制单个 IP 建立新连接的速度。
Apache 负责处理已经进入服务器的 HTTP 请求。
CDN、WAF 和云厂商负责在服务器上游处理分布式攻击、带宽型攻击和应用层请求洪水。
最小防护结构只需要保留三个核心方向:已经确认的恶意来源进入 mw_ban,单 IP 并发连接过高由 connlimit 处理,单 IP 建立新连接过快由 hashlimit 处理。
防火墙规则的价值不在于数量,而在于每条规则都明确知道自己限制的对象。