为 Web 应用设置 iptables
`iptables` 软件包让我们能够对防火墙进行高级、精细的控制,并具有过滤和限制等重要的内置功能。本指南将介绍一种更高级的方法,利用上述功能、包含的 `conntrack` 模块和限制规则,同时探索潜在的安全风险。
本指南中使用的每个命令(“man”除外)都需要提升的权限,因此我在所有命令前面都添加了“sudo”,以便更容易地复制所有内容(当然,经过仔细检查之后)。
我们将实施遵循状态防火墙概念所规定的原则的防火墙。
本指南中介绍的配置已在本地 Ubuntu 24.04 虚拟机和云 Ubuntu 22.04 虚拟机上进行了测试。两者都安装了 Apache2 并启用了 HTTP/HTTPS 规则测试。测试包括发出和接收 HTTP/HTTPS 请求、检查“apt”连接、使用“dig”命令以及从客户端到虚拟机使用“ping”。
此配置与 LAMP、LEMP 和 MERN 堆栈兼容,并且也应与其他类似的堆栈一起使用。
最初,这是我的“设置 LAMP(堆栈)”指南的一部分,但我决定将其拆分为单独的出版物,以避免让新手感到不知所措。
本指南也可在 Medium 上获取。
手册和文档

我们鼓励您查看本指南中我们将使用的命令的文档。可以使用“man iptables”访问 Linux 命令文档和手册。
一些手册还提供了有关如何执行某些操作的示例。
或者,您可以使用“iptables -h”获取摘要详细信息和选项列表。
防火墙如何工作?
所有防火墙环境都使用相同或相似的术语。概念保持不变。当我们设置防火墙规则时,我们会将这些规则添加到特定的 上。此时无需详细说明表格,因为通常情况下,在这种情况下,我们将仅处理默认的“过滤器”表。
常见的连锁店有:
由于我们正在为 Web 服务器计算机设置防火墙,因此我假设您想要托管网站或其他 Web 应用程序。这意味着我们需要打开端口“80”(HTTP)和“443”(HTTPS)。最重要的是,我们需要打开 SSH/SFTP 端口“22”(SFTP 本质上是通过 SSH 的 FTP,这意味着它也使用端口“22”),以保持与我们的计算机的远程通信畅通。这些端口仅使用 TCP 协议。我们还将允许有限的 ICMP(ping)流量和 DNS 查找(通过 UDP 的端口“53”)。
请记住,如果您更改了 SSH 端口,则必须使用自定义端口而不是默认的“22”!
在标准防火墙解决方案中,规则的处理顺序与添加的顺序相同。在命令行界面 (CLI) 中,这一点尤其重要。在图形用户界面 (GUI) 中,通常允许您移动内容,但在这两种情况下,顺序错误都可能导致严重问题,包括完全锁定。
如果您确实无法远程访问,大多数提供虚拟机的供应商也会提供 Web 终端或通过现场支持直接访问。如果不是这种情况,请不要羞于放弃安装并从头开始重试。这都是学习过程的一部分。
使用 iptables
正如您可能在手册中看到的,有很多命令、标志和参数。让我们来看看一些有用的基本命令。我们将跳过规则附加部分,因为我们稍后会详细介绍它们。
要获取所有链的当前规则及其相应位置,请使用:
sudo iptables -L -vn --line-numbers
要从特定链中删除特定规则,您应该通过上一个命令查找它,然后使用:
sudo iptables -D {chain} {rule-id}
规则持久性
直接通过 `iptables` 定义的规则是短暂的,这意味着它们是临时的,并且仅在会话期间存在。如果我们重新启动服务器而不保存它们,它们就会消失。
因此,我们还需要“iptables”之上的“iptables-persistent”包。它基本上是一个“systemd”服务,每次机器启动时都会加载你的规则。
要保存配置,我们可以使用以下命令:
sudo netfilter-persistent save
**危险:**规则添加后立即生效!此命令仅保存它们,以便在重启后重新加载它们!
设置
通常,您需要为特定端口设置 INPUT 和 OUTPUT 规则,以便您的服务器可以接收和响应来自互联网的请求。我们将更进一步。
当有人访问我们的服务器时,他们会发送请求,从而建立连接。在第一个请求中,状态为“NEW”,但此后的所有请求都具有“ESTABLISHED”或“RELATED”(与现有连接;辅助连接)状态。当然,这在其他协议上可能会有所不同,但 HTTP/HTTPS 并没有那么花哨。
我们将采取平衡的做法,采取以下措施:
此设置提供了坚实的基础并限制了潜在的暴露面,同时允许相当自由的标准 HTTP/HTTPS 流量流动。
理论上,如果您使用 NGINX 作为反向代理,您也可以将此设置与 MERN 堆栈一起使用。由于 Node.js 和 NGINX 之间的流量是内部的,因此它将顺利地通过保持打开的环回接口流动。
安全注意事项
一旦你将服务器或机器暴露在互联网上,你就会注意到总会有人或某物在扫描和探测它。要么试图使用流行的不安全凭据闯入,要么扫描开放端口,要么检查你部署的 Web 应用程序是否存在常见的配置错误或环境漏洞。
需要强调的是,安全不是目标或目的地,而是指导我们行动的指令。你无法实现安全,但你可以尽力减轻恶意活动。未来需要记住的另一件事是:**通过隐蔽性实现的安全不是真正的安全**。这是一种有缺陷的安全原则,它注重保密而不是实际保护。
在某些情况下,ICMP 可能被恶意用作隧道方法。我们将通过阻止除入站“echo-request”类型消息和传出“echo-reply, destination-unreachable”消息之外的所有 ICMP 来缓解这种情况。这将允许外部机器 ping 我们(对于基本健康检查很有用),但阻止我们的服务器发送除基本响应之外的任何 ICMP 消息,并限制 ICMP 隧道攻击的可能性,但不能完全根除它。如果您不打算使用 ICMP,请随意在您的配置中不包含这些规则或稍后将其删除。
DNS 可以做类似的事情,这就是我们也限制端口“53”UDP 上的流量的原因。
服务器本身不应该能够在没有任何保护措施的情况下发送传出请求。开放传出通信会增加病毒或代码执行漏洞引发的数据泄露风险。此配置是一个很好的基础,但如果您想更进一步,在安装完所有内容后,您应该删除允许作为客户端进行外部连接的规则,而只允许向特定 IP 地址进行传出客户端通信。我们将在本指南的最后介绍此过程。
在速率限制方面,我建议不要使用标准的 `iptables` 限制功能,因为这不会区分合法连接和暴力攻击。即使对具有 `NEW` 状态的数据包设置速率限制,也会导致在您尝试在暴力攻击或常规漏洞探测/扫描期间连接的情况下被锁定。您应该使用专门的实用程序,例如 `fail2ban` 来实现此目的。
**在开始配置之前,我们必须明白,如果攻击者直接获得了服务器的访问权限,我们的防火墙将无法阻止他们。**
配置
防止不需要的传出 HTTP/HTTPS
按照服务器本身不应该在自身上建立新连接(充当客户端)的想法,我们应该禁用潜在的不安全规则来锁定我们的服务器,同时允许其提供网络内容所需的最低限度。
如前所述,如果您在服务器端调用任何外部 API,即在您的 PHP 代码中(或在服务器端呈现的 JavaScript 应用程序中),则必须保留这些规则以避免出现连接问题。删除它们还将导致所有将外部数据拉入您计算机的软件包无法运行,最重要的是“apt/apt-get”和“curl”。
幸运的是,至少从管理角度来说,还是有解决方案的。我个人知道的有:
在所有情况下都会有一些开销。
使用此代码片段删除客户端规则:
sudo iptables -D INPUT -p tcp --sport 80 -m conntrack --ctstate ESTABLISHED -j ACCEPT; \ sudo iptables -D INPUT -p tcp --sport 443 -m conntrack --ctstate ESTABLISHED -j ACCEPT; \ sudo iptables -D OUTPUT -p tcp --dport 80 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT; \ sudo iptables -D OUTPUT -p tcp --dport 443 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT
当你需要它们时,可以使用此代码片段将它们放回去:
sudo iptables -A INPUT -p tcp --sport 80 -m conntrack --ctstate ESTABLISHED -j ACCEPT; \ sudo iptables -A INPUT -p tcp --sport 443 -m conntrack --ctstate ESTABLISHED -j ACCEPT; \ sudo iptables -A OUTPUT -p tcp --dport 80 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT; \ sudo iptables -A OUTPUT -p tcp --dport 443 -m conntrack --ctstate NEW,ESTABLISHED -j
**恭喜!您已提高服务器的安全性。**
发现错误?请告诉我!
感谢您的阅读。希望本指南能提供一些价值 :)