大家好!
我正在尝试使用 iptables 设置我的服务器防火墙(我必须承认我上次使用 iptables 是在一年前),但是 iptables 的行为与我的要求相反。
这是我的测试脚本:
#!/bin/sh
IPT="/sbin/iptables"
echo -n "Loading iptables rules..."
# Flush old rules
$IPT --flush
$IPT --delete-chain
# Allow incoming and outgoing for loopback interfaces
$IPT -A INPUT -i lo -j ACCEPT
$IPT -A OUTPUT -o lo -j ACCEPT
# Allow incoming traffic for HTTP(S), SSH and SMTP
$IPT -A INPUT -p tcp --dport 80 -i eth0 -j ACCEPT
$IPT -A INPUT -p tcp --dport 443 -i eth0 -j ACCEPT
$IPT -A INPUT -p tcp --dport 22 -j ACCEPT
$IPT -A INPUT -p tcp --dport 25 -i eth0 -j ACCEPT
# Allow ICMP requests
$IPT -A INPUT -p icmp -i eth0 -j ACCEPT
$IPT -A OUTPUT -p icmp -o eth0 -j ACCEPT
# Allow outgoing traffic for SMTP, DNS, NTP, PgSQL, SolR, and SSH
$IPT -A OUTPUT -p tcp --dport 25 -o eth0 -j ACCEPT
$IPT -A OUTPUT -p tcp --dport 53 -o eth0 -j ACCEPT
$IPT -A OUTPUT -p udp --dport 53 -o eth0 -j ACCEPT
$IPT -A OUTPUT -p udp --dport 123 -o eth0 -j ACCEPT
$IPT -A OUTPUT -p tcp --dport 5433 -o eth0.2654 -j ACCEPT
$IPT -A OUTPUT -p udp --dport 5433 -o eth0.2654 -j ACCEPT
$IPT -A OUTPUT -p tcp --dport 8983 -o eth0.2654 -j ACCEPT
$IPT -A OUTPUT -p udp --dport 8983 -o eth0.2654 -j ACCEPT
$IPT -A OUTPUT -p tcp --dport 22 -o eth0 -j ACCEPT
$IPT -A OUTPUT -p tcp --dport 22 -o eth0.2654 -j ACCEPT
# Deny web server user outgoing connections
$IPT -A OUTPUT -o eth0 -m owner --uid-owner www-data -j DROP
# Drop everything else
$IPT -A INPUT -j DROP
$IPT -A OUTPUT -j DROP
$IPT -A FORWARD -j DROP
echo "rules loaded."
# Print rules as understood, then flush to avoid lockout
sleep 10
$IPT -L
# Flush old rules
$IPT --flush
$IPT --delete-chain
使用此脚本,服务器不再回答除 ping(ICMP)之外的任何请求,然后,10 秒后,打印以下文本并退出:
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
100 5920 ACCEPT all -- lo any anywhere anywhere
0 0 ACCEPT tcp -- eth0 any anywhere anywhere tcp dpt:www
0 0 ACCEPT tcp -- eth0 any anywhere anywhere tcp dpt:https
1 52 ACCEPT tcp -- any any anywhere anywhere tcp dpt:ssh
0 0 ACCEPT tcp -- eth0 any anywhere anywhere tcp dpt:smtp
0 0 ACCEPT icmp -- eth0 any anywhere anywhere
0 0 DROP all -- any any anywhere anywhere
Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
0 0 DROP all -- any any anywhere anywhere
Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
100 5920 ACCEPT all -- any lo anywhere anywhere
0 0 ACCEPT icmp -- any eth0 anywhere anywhere
0 0 ACCEPT tcp -- any eth0 anywhere anywhere tcp dpt:smtp
0 0 ACCEPT tcp -- any eth0 anywhere anywhere tcp dpt:domain
0 0 ACCEPT udp -- any eth0 anywhere anywhere udp dpt:domain
0 0 ACCEPT udp -- any eth0 anywhere anywhere udp dpt:ntp
0 0 ACCEPT tcp -- any eth0.2654 anywhere anywhere tcp dpt:5433
0 0 ACCEPT udp -- any eth0.2654 anywhere anywhere udp dpt:5433
0 0 ACCEPT tcp -- any eth0.2654 anywhere anywhere tcp dpt:8983
0 0 ACCEPT udp -- any eth0.2654 anywhere anywhere udp dpt:8983
0 0 ACCEPT tcp -- any eth0 anywhere anywhere tcp dpt:ssh
0 0 ACCEPT tcp -- any eth0.2654 anywhere anywhere tcp dpt:ssh
0 0 DROP all -- any eth0 anywhere anywhere owner UID match www-data
14 2061 DROP all -- any any anywhere anywhere
第一个令人不安的元素,我注意到 INPUT 和 OUTPUT 的第一条规则是接受所有数据包,而我并没有要求这样做。此外,我尝试将 INPUT 和 OUTPUT 的策略设置为 DROP(使用$IPT -P INPUT DROP
和$IPT -P OUTPUT DROP
),但这样做最终将我锁定,即使在十秒超时之后也是如此,并且服务器只响应 ICMP,这迫使我硬重启服务器。如果我在脚本开头设置策略设置,效果相同。
我怀疑我的错误对于普通 iptables 用户来说很明显,但我已经搜索了几个小时的解决方案,而且,就像在这种情况下一样,只有有人指出来,答案才会对我显而易见。请问有哪位好心人能帮助我吗?
eth0.2654
是用于与我们的 PgSQL 服务器通信的 VLAN。关于 HTTP 答案,我的印象是它们使用客户端打开的连接,这是我的规则允许的。我错了吗?
答案1
关于 HTTP 答案,我的印象是它们使用客户端打开的连接,这是我的规则允许的。我错了吗?
是的,你错了。你很可能想要接受已建立的连接或与传入连接相关的连接。因此,输入规则上接受的任何内容都可以得到回答。使用无状态防火墙,必须明确打开源端口。由于 IPtables 是有状态的,因此你不需要这样做。它将跟踪你的连接状态并自动按照你的想法允许出站连接,但前提是你告诉它这样做。此规则是iptables -A INPUT -p ALL -m state --state ESTABLISHED,RELATED -j ACCEPT
。将其放在输出列表的顶部。如果你想特别积极,你可以将该规则绑定到特定端口。
如果您以无状态的方式看待这个问题,您必须记住数据包来自哪里以及要去哪里。您当前已将服务器设置为允许您通过 SSH 连接到另一台计算机。由于您不允许任何以端口 22 为源的流量,因此您的服务器无法响应传入连接。同样,“ESTABLISHED,RELATED”规则解决了这个问题,允许流量响应入站连接,就像允许来自端口 22 的流量一样,但与在无状态防火墙上打开 22 不同,此设置不允许从那里开始新连接。
答案2
你的方法很糟糕。你允许所有输入连接,然后在输出时停止它们。这不会阻止 DDoS 攻击。正确的方法是停止输入连接并允许输出。
通读你的代码后,我尝试重新制作。我认为它应该是这样的:
#!/bin/sh
IPT=/usr/sbin/iptables
echo "Clear firewall rules..."
$IPT -F
$IPT -Z
$IPT -t nat -F
$IPT -t nat -Z
$IPT -t mangle -F
$IPT -t mangle -Z
$IPT -X
echo "Setting firewall policy..."
$IPT -P INPUT DROP # Deny all incoming connections
$IPT -P OUTPUT ACCEPT # Allow all outgoing connections
$IPT -P FORWARD DROP # Deny all forwaring
echo "Allow connections from: lo, eth0, eth0.2654"
$IPT -I INPUT -i lo -j ACCEPT
$IPT -I INPUT -i eth0 -j ACCEPT
echo "Allow icmp requests from eth0"
$IPT -A INPUT -p icmp -i eth0 -j ACCEPT
echo "Allow traffic for HTTP(S), SSH, SMTP, DNS, NTP, PgSQL, SolR"
$IPT -A INPUT -p tcp --dport 22 -j ACCEPT
$IPT -A INPUT -p tcp --dport 25 -i eth0 -j ACCEPT
$IPT -A INPUT -p tcp --dport 53 -i eth0 -j ACCEPT
$IPT -A INPUT -p udp --dport 53 -i eth0 -j ACCEPT
$IPT -A INPUT -p tcp --dport 80 -i eth0 -j ACCEPT
$IPT -A INPUT -p udp --dport 123 -i eth0 -j ACCEPT
$IPT -A INPUT -p tcp --dport 443 -i eth0 -j ACCEPT
$IPT -A INPUT -p tcp --dport 5433 -i eth0.2654 -j ACCEPT
$IPT -A INPUT -p udp --dport 5433 -i eth0.2654 -j ACCEPT
$IPT -A INPUT -p tcp --dport 8983 -i eth0.2654 -j ACCEPT
$IPT -A INPUT -p udp --dport 8983 -i eth0.2654 -j ACCEPT
echo "Deny web server user outgoing connections; eth0"
$IPT -A INPUT -o eth0 -m owner --uid-owner www-data -j DROP
echo "Drop everything."
$IPT -A INPUT -s 0/0 -j DROP
echo "Firewall loaded."
sleep 20
$IPT -nvL
echo "Clear firewall rules..."
$IPT -F
$IPT -Z
$IPT -t nat -F
$IPT -t nat -Z
$IPT -t mangle -F
$IPT -t mangle -Z
$IPT -X
我还没有测试过,所以请记住这一点。我不确定“-i eth0.2654”是否适用于虚拟接口。
如果您愿意,请尝试一下,然后告诉我是否有效。