安全运维中几条实用的 iptables 规则总结



案例一

假设运行 iptables 的 Linux 主机作为企业的网关防火墙,

其上有2个以太网卡:eth0 连接 Internet,使用公网 IP ;eth1 连接企业内网,使用局域网 IP,要限制内网用户访问  www.evil.com   

iptables -A OUTPUT -o eth0 -p tcp -d www.evil.com --dport 80 -j DROP

或者

iptables -A OUTPUT -o eth0 -p tcp -d ! www.evil.com  --dport 80 -j ACCEPT

注意,如果这里的策略不能生效,将域名换为 FQDN ,即   www.evil.com.

另外,因为没有使用 iptables 的扩展模块,所以域名会进行 DNS 解析,得到结果后才向内存写入该条策略;这意味着,必须分别在出站方向放行 UDP 的目标端口 53 ;在入站方向放行 UDP 的源端口 53




案例二

网络拓扑同案例一,假设企业有内部网站,并且只允许员工访问其内部站点

iptables -A FORWARD -i eth1 -o eth0 -p tcp --dport 80 -j DROP

eth0 和 eth1 是以太网接口;Linux 支持的其它类型网络接口,常见的有:


ppp0      第一个 PPPOE(以太网上的点到点协议) 接口

lo        本地环回接口,即 127.0.0.1

fddi0     第一个光纤数字用户设备接口,即光纤接口



案例三

假设运行 iptables 的 Linux 主机作为 SSH 服务器,IP 地址为  192.168.0.1


把每个尝试远程 ssh 登录的客户端 IP 记录在一个临时列表中,只要列表中的 IP一小时以内,尝试登录次数达到3次(包括密码输错3次,以及重复登录-退出达到3次,以及连续登录达到3次,例如连开3个 putty 登录)

第3次登录时将被拒绝,持续一小时后才能再次登录,注意,前2次成功的登录并不会断开,除非你自行退出,否则已经成功的登录会话将保持连接,后续的登录尝试将被拒绝一小时

下面这3条规则必须一起使用,并且假设第一条规则将添加至 INPUT 链的第一条规则,注意 -I 选项后接的 INPUT 链规则编号,按照这里的操作输入,这3条规则将变成 INPUT 链的前3条规则,从而达到优先匹配进站的 SSH 连接请求的目的:


iptables -I INPUT  -d 192.168.0.1 -p tcp -m tcp --dport 22 -m state --state NEW -m recent --set --name SSH
iptables -I INPUT 2  -d 192.168.0.1 -p tcp -m tcp --dport 22 -m state --state NEW -m recent --update --seconds 3600 --hitcount 3 --name SSH -j DROP
iptables -I INPUT 3  -d 192.168.0.1 -p tcp -m tcp --dport 22 -j ACCEPT

这对于阻止暴力破解 SSH 登录的弱口令非常有效,当然,设置足够健壮,复杂,易于记忆的密码,也是必需的


案例四

运维管理员在运行 iptables 的 Linux 网关主机上检测到来自某个 B 类 IP 网段

172.16.0.0/16

的频繁扫描流量,希望设置 iptables 规则封堵该 IP 地址段的 65534 台可疑主机,两小时后解封

iptables -I INPUT -s 172.16.0.0/16 -j DROP
iptables -I FORWARD -s 172.16.0.0/16 -j DROP
at now +2 hours
iptables -D INPUT 1
iptables -D FORWARD 1
                             //此处按Ctrl+D组合键
job 4 at 2014-10-01 09:26



案例五

场景类似案例四,但是这次允许转发来自 C类 IP 网段

192.168.0.0/24  中 253 台主机的 DNS 解析请求与本地 DNS 回送的 DNS 应答数据包,在案例四的策略基础上,再添加下面规则:

iptables -A FORWARD -s 192.168.0.0/24 -p udp --dport 53 -j ACCEPT
iptables -A FORWARD -d 192.168.0.0/24 -p udp --sport 53 -j ACCEPT


案例六:结合NAT与FILTER表实现允许内网特定主机使用公网IP访问特定互联网服务。

假设企业内部一台作为网关路由器的 CentOS 上有2块网卡:eth0 的 IP 101.102.103.104 连接公网,网卡eth1 的 IP 172.16.1.1 连接内网 172.16.1.0/24,

(拓扑如图一所示)

安全运维中几条实用的 iptables 规则总结_第1张图片

要实现内网中其它计算机共用公网IP访问互联网,则需要在作为网关路由器上的Linux上制定下列 iptables 规则(规则一):

iptables -t nat -A POSTROUTING -s 172.16.1.0/24 -o eth0 -j SNAT --to-source 101.102.103.104

上述规则表示来自源地址(-s)范围 172.16.1.0/24 的数据包在经过路由后(POSTROUTING),从 eth0 网卡出去前(-o),将源 IP 转换(SNAT --to-source)为 101.102.103.104;注意,如果是在供 iptables-restore 读取的规则文件中编写,则可以省略 “iptanles -t -nat”前缀,前提是该规则位于“*nat”字段下。


如果图一中的 CentOS 路由器前端还有一个使用 PPPoE 协议拨号的 ADSL/Cable Modem,那么从 ISP 分配到的公网 IP 通常是动态的,每隔一段时间会自动协商并且更新一次(当然现在的企业很少是这种情况,企业通常向 ISP 租用能分配到多个静态公网 IP 的专线),此时就需要将规则一改成下列:

iptables -t nat -A POSTROUTING -s 172.16.1.0/24 -o eth0 -j SNAT MASQUERADE

 这样 NetFilter 内核模块将自动使用动态公网IP进行转换;


如果图一中的 CentOS 路由器本身就带有 PPPoE 拨号所需的特殊接口网卡(这类接口通常是由家用路由器或者Cisco等大型互联网路由器提供),那么需要将规则一改成下列:

iptables -t nat -A POSTROUTING -s 172.16.1.0/24 -o pppX -j SNAT --to-source 101.102.103.104

上述规则中的X值取决于你的网络环境,可以使用 ifconfig 查看。


如果图一中的 CentOS 路由器的网卡 eth0 从 ISP 分配到多个静态公网 IP:

101.102.103.104~101.102.103.110,要实现内网计算机“轮询”使用这7个公网IP 访问互联网,则需要将规则一改成下列:

iptables -t nat -A POSTROUTING -s 172.16.1.0/24 -o eth0 -j SNAT --to-source 101.102.103.104-101.102.103.110



在前面 nat 表的 POSTROUTING 链的 SNAT 例子中,仅仅实现了公网 IP——内网IP 的转换,假设现在图一中的 PC 1(172.16.1.2 )要使用路由器的公网 IP 访问互联网上的 web(即HTTP,web服务器监听在 TCP 80端口)服务,则需要进一步在 iptables 的 filter 表中指定相应的规则如下:

iptables -t filter -A FORWARD -s 172.16.1.2/32 -i eth1 -o eth0 -p tcp -m tcp --dport 80 -j ACCEPT

上述规则表示允许转发从网卡 eth1 进入(-i eth1),从网卡 eth0 出去(-o eth0);源地址为 172.16.1.2,协议为 tcp(-p tcp ),目标端口为 80(--dport 80)的数据包。

注意,在制定上述规则前需要确认 filter 表的 forward 链的默认规则为 drop,意味着默认禁止在内外网转发所有数据包,然后再像上面这样逐一去“开通”允许转发的数据包特征,这也就是让 iptables 基于白名单匹配的规则制定思路。

选择 forward 链的原因在于,来自或去往 172.16.1.0/24 网段的数据包需要经由本路由器路由决策后“转发”(forward)。

我们知道,TCP连接是双向的,光有上面这条转发规则还不够,因为这样只能让数据包从内网出去;应答的数据包不能从外网进来,因此需要下面这条规则一起使用,注意所有的参数都取决于数据包流向而改变: 

iptables -t filter -A FORWARD -d 172.16.1.2/32 -i eth0 -o eth1 -p tcp -m tcp --sport 80 -j ACCEPT


再次参考图一。由于反方向回来的数据包会自动通过 nat 表的 PREROUTING 链执行转换,再通过 filter 表过滤,因此 forward 链在匹配时都是转换后的内网 IP(此例中),如下书写规则将导致 iptables 无法转发数据包:

iptables -t filter -A FORWARD -d 101.102.103.104 -i eth0 -o eth1 -p tcp -m tcp --sport 80 -j ACCEPT


上面 2 条规则和 nat 表的 SNAT 规则一起使用,仅实现了 172.16.1.2 这台主机使用公网 IP 访问互联网的 HTTP(80端口)服务,要访问 HTTPS 服务(HTTP Over SSL,web 服务器监听在 TCP 443端口)和域名解析,还需要允许TCP 443 和 UDP 53端口,并且应该将域名解析的规则放在 HTTP 和 HTTPS的规则之前,如下:

iptables -t filter -A FORWARD -s 172.16.1.2/32 -i eth1 -o eth0 -p udp -m udp --dport 53 -j ACCEPT 
iptables -t filter -A FORWARD -d 172.16.1.2/32 -i eth0 -o eth1 -p udp -m udp --sport 53 -j ACCEPT 
iptables -t filter -A FORWARD -s 172.16.1.2/32 -i eth1 -o eth0 -p tcp -m tcp --dport 80 -j ACCEPT
iptables -t filter -A FORWARD -d 172.16.1.2/32 -i eth0 -o eth1 -p tcp -m tcp --sport 80 -j ACCEPT

 这样就实现了通过iptables允许内网特定主机使用公网IP访问特定互联网服务。

我们也可以直接用文本编辑器编写规则,具体书写语法可以参考用 iptables-save

命令生成的规则文件,当然也可以直接对其进行修改。如果要实现系统在启动时自动读取该文件中的规则来过滤,则需要在 /etc/rc.d/rc.local 配置文件中添加一行:

/sbin/iptables-restore < /root/桌面/my-iptables-rule

上面假定规则文件的存放位置在 /root/桌面,名为 my-iptables-rule,并且需要

iptables 命令的完整路径(可以使用 whereis iptables 查找),最后,记得将文件的所有者与所属主改成 root,权限改为 700


案例七:通过NAT表实现多个内网服务器共用一个公网IP对外提供服务(NATP,网络地址端口转换)。


假设企业内部一台作为网关路由器的 CentOS 上有3块网卡:eth0 的 IP 101.102.103.104 连接公网,网卡eth1 的 IP 172.16.1.1 连接内网 172.16.1.0/24,网卡 eth2 的 IP 192.168.1.1 连接内网 192.168.1.0/24;

内网 192.168.1.0/24 作为非军事防御区(DMZ),其中一台 Server1 IP 为

192.168.1.2,对外提供HTTP+HTTPS 服务,另一台 Sever2 IP 为 192.168.1.3,

对外提供传统 Mail 服务(非 web mail),

(拓扑如图二所示)


安全运维中几条实用的 iptables 规则总结_第2张图片


要实现互联网用户能够访问 DMZ 中Sever1 上的 HTTP/S 服务,需要在CentOS上制定下列 iptables 规则:


iptables -t nat -A PREROUTING -i eth0 -p tcp -m tcp --dport 80 -j DNAT --to 192.168.1.2:80
iptables -t nat -A PREROUTING -i eth0 -p tcp -m tcp --dport 443 -j DNAT --to 192.168.1.2:443


结合图二,不难看出上述规则就是将入站方向请求连接 CentOS 公网 IP 的 TCP目标端口80和443的数据包在路由前,将其目标地址转换为 DMZ中 Servre1 的相应地址和端口,然后路由至相应网段;对于Sever2上的 Mail 服务,以及使用其它应用层协议的服务,制定规则类似:


iptables -t nat -A PREROUTING -i eth0 -p tcp -m tcp --dport 25 -j DNAT --to 192.168.1.3:25
iptables -t nat -A PREROUTING -i eth0 -p tcp -m tcp --dport 110 -j DNAT --to 192.168.1.3:110


另外,如果Sever1也需要主动(TCP数据包的状态非ESTABLISHED,而是 NEW)访问互联网上的其它服务器(下载更新软件和安全补丁),还需要添加下列规则:

iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -o eth0 -j SNAT --to 101.102.103.104

结合图二应该可以很容易了解上述规则中的各项参数作用,另外,规则中的 -s 192.168.1.0/24 ,意味着 Sever2 也可以主动访问互联网了。


案例八 :制定 iptables 安全规则实现阻挡 NMAP, Hping 等网络扫描工具发出的探测包

上述踩点工具通常会在全端口范围内(1-65535)扫描目标的开放端口,然后尝试枚举相应服务的版本,漏洞,其原理无非是发出带有特定 TCP 标识位组合的扫描包,然后通过目标返回的响应来判断,因此我们可以通过 iptables 丢弃这些探测包,从而保证网关和内网主机安全,具体规则如下:

丢弃隐蔽扫描包:

iptables -t filter -A INPUT -p tcp --tcp-flags SYN,FIN SYN,FIN -j DROP


丢弃所有标识位都清位的扫描包(NMAP中的NULL扫描):


iptables -t filter -A INPUT -p tcp --tcp-flags ALL NONE -j DROP



丢弃SYN和RST都置位的扫描包:

iptables -t filter -A INPUT -p tcp --tcp-flags SYN,RST SYN,RST -j DROP


丢弃FIN和RST都置位的扫描包:

iptables -t filter -A INPUT -p tcp --tcp-flags FIN,RST SYN,RST -j DROP


丢弃只有FIN置位,没有预期与ACK一起置位的扫描包(NMAP的XMAS扫描之一):

iptables -t filter -A INPUT -p tcp --tcp-flags ACK,FIN FIN -j DROP


丢弃只有PSH置位,没有预期与ACK一起置位的扫描包(NMAP的XMAS扫描之一)

iptables -t filter -A INPUT -p tcp --tcp-flags ACK,PSH PSH -j DROP


丢弃只有URG置位,没有预期与ACK一起置位的扫描包(NMAP的XMAS扫描之一)

iptables -t filter -A INPUT -p tcp --tcp-flags ACK,URG URG -j DROP



案例九:一个作为个人桌面型PC使用的 Linux  iptables 规则文件,使用 iptables-save 自动生成,可以作为日后自行编写规则文件的基础模板:


# Generated by iptables-save v1.4.7 on Sun Aug 30 22:18:39 2015
*nat
:PREROUTING ACCEPT [0:0]
:POSTROUTING ACCEPT [367:22484]
:OUTPUT ACCEPT [370:22712]
COMMIT
# Completed on Sun Aug 30 22:18:39 2015
# Generated by iptables-save v1.4.7 on Sun Aug 30 22:18:39 2015
*mangle
:PREROUTING ACCEPT [13883:18761885]
:INPUT ACCEPT [13883:18761885]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [8935:760997]
:POSTROUTING ACCEPT [8932:760769]
COMMIT
# Completed on Sun Aug 30 22:18:39 2015
# Generated by iptables-save v1.4.7 on Sun Aug 30 22:18:39 2015
*filter
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT DROP [3:228]
-A INPUT -m state --state NEW -j DROP 
-A INPUT -p tcp -m tcp --tcp-flags FIN,SYN FIN,SYN -j DROP 
-A INPUT -p tcp -m tcp --tcp-flags FIN,SYN,RST,PSH,ACK,URG NONE -j DROP 
-A INPUT -p tcp -m tcp --tcp-flags SYN,RST SYN,RST -j DROP 
-A INPUT -p tcp -m tcp --tcp-flags FIN,RST SYN,RST -j DROP 
-A INPUT -p tcp -m tcp --tcp-flags FIN,ACK FIN -j DROP 
-A INPUT -p tcp -m tcp --tcp-flags PSH,ACK PSH -j DROP 
-A INPUT -p tcp -m tcp --tcp-flags ACK,URG URG -j DROP 
-A INPUT -i lo -j ACCEPT 
-A INPUT -p udp -m udp --sport 53 -j ACCEPT 
-A INPUT -p tcp -m tcp --sport 80 -j ACCEPT 
-A INPUT -p tcp -m tcp --sport 443 -j ACCEPT 
-A OUTPUT -o lo -j ACCEPT 
-A OUTPUT -p udp -m udp --dport 53 -j ACCEPT 
-A OUTPUT -p tcp -m tcp --dport 80 -j ACCEPT 
-A OUTPUT -p tcp -m tcp --dport 443 -j ACCEPT 
-A OUTPUT -p tcp -m multiport --dports 1024:65535 -j LOG 
-A OUTPUT -p udp -m multiport --dports 1024:65535 -j LOG 
COMMIT
# Completed on Sun Aug 30 22:18:39 2015


注意部署最后2条规则的用意:

一般情况,从本地出站的主动请求连接的数据包,应该都是访问互联网上公用服务如 80,443,53,22 等目标端口的数据包,也就是 dport 为 1024 以下的,如果 dport 在 1024 以上的出站包,就有问题了,有可能是连接目标机上 P2P 对等点或者反弹式***/ rootkit 客户端开放的高位端口,因此我们可以将其记录下来并查看日志,追踪其目标地址(配合 rsyslog 服务),这是通过 iptables 的 multiport 模块实现的,连续端口用冒号连接,非连续端口用逗号隔开。


该文件中的策略安全性还可以进一步加强,例如,将 nat表中的三个链默认动作设置为 drop;

并且,如果该表使用在NAT网关路由器上,还需要执行下列命令开启内核转发 IPv4 数据包的功能:

echo 1 > /proc/sys/net/ipv4/ip_forward

或者

vim /etc/sysctl.conf
net.ipv4.ip_forward = 1


由于 /proc 路径下的所有内容实际在内存中,即基于内存的虚拟文件系统,因此第一种方法只能临时生效,重启后失效(内存是易失性存储器)

第二种方法修改的是磁盘上的文件,由内核每次在启动时读取,因为磁盘是非易失的,因此永久有效。