使用 iptables 阻止特定 Linux 用户的出站流量(保持监听端口正常工作)
Source: Dev.to
目标
针对 userA:
- 阻止 新建的出站连接(例如
curl、软件包下载、外部 API 调用)。 - 保持 端口监听 和 入站服务响应 正常工作(例如守护进程绑定到
0.0.0.0:8080并响应远程客户端)。
关键是向 OUTPUT 链添加一条规则,匹配该用户并仅在 conntrack 状态为 NEW 时丢弃/拒绝流量。
前置条件
- root 权限(
sudo)。 - 支持
conntrack(大多数现代 Linux 系统均已提供)。 - 用户的 UID(推荐使用 UID,以确保准确匹配)。
获取用户的 UID
id -u userA
将下面命令中的空白处替换为返回的数字。
应用 iptables 规则(IPv4)
首先允许已建立的流量(重要)
sudo iptables -I OUTPUT 1 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
允许环回流量(推荐)
sudo iptables -I OUTPUT 2 -o lo -j ACCEPT
阻止该用户的 NEW 出站连接(核心规则)
sudo iptables -I OUTPUT 3 -m owner --uid-owner <UID> -m conntrack --ctstate NEW -j REJECT
注意:
REJECT会快速返回错误,便于调试。若想静默阻断,可使用DROP。owner匹配仅对本地主机生成的数据包(OUTPUT)有效,这正是我们需要的。
为什么这能保持监听端口正常工作
用户进程仍然可以:
- 绑定并监听端口(仅仅监听本身并不产生网络传输)。
- 接受由远程客户端发起的入站连接。
当远程主机连接到你的服务时,服务器的响应属于已经建立的连接。这些响应数据包被标记为 ESTABLISHED,因此会被第一条规则放行。
结果
- 出站连接的发起被阻止。
- 入站服务照常运行。
验证规则
sudo iptables -S OUTPUT
sudo iptables -L OUTPUT -n -v --line-numbers
测试思路
以 userA 身份尝试:
curl https://example.com # 应该失败
在另一台主机上,连接 userA 监听的服务:
nc 8080 # 应该能够连接并收到响应
不要忘记 IPv6(常见的绕过方式)
如果启用了 IPv6,请使用等效的 ip6tables 规则:
sudo ip6tables -I OUTPUT 1 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
sudo ip6tables -I OUTPUT 2 -o lo -j ACCEPT
sudo ip6tables -I OUTPUT 3 -m owner --uid-owner <UID> -m conntrack --ctstate NEW -j REJECT
运行时注意事项与警告
-
-m owner仅适用于 OUTPUT
owner模块只匹配本地主机上的进程,仅对本地产生的流量有意义。它不适用于转发流量(FORWARD)或其他主机的流量。 -
特权提升可以绕过限制
若userA能以其他用户身份运行命令(例如通过sudo提升为 root),其流量将归属不同的 UID,因而不会匹配本规则。请通过收紧 sudo 策略和系统加固来降低风险。 -
已有连接可能仍保持打开
由于规则仅阻止NEW,任何已建立的出站连接会继续存在直至自然关闭。若需立即切断,可终止相应进程或使用ss/lsof等工具杀掉现有连接。
结论
使用 iptables 为特定 Linux 用户阻止出站流量,同时保持监听端口正常工作,步骤如下:
- 允许
ESTABLISHED,RELATED流量。 - 允许环回流量。
- 在 OUTPUT 链中拒绝(或丢弃)用户拥有的
NEW出站连接。
这种最小侵入式的方法非常适合需要限制出站但不影响入站服务行为的服务账号。