0x00 概述
iptables 是 Linux 内核集成一套包过滤系统,并且可以实现状态防火墙,建立精细的包过滤列表,功能十分强大,所以选择折腾 iptables 来实现防火墙。
iptables 一共有 4 个表:filter,nat,mangle,raw
,5 个链:INPUT,OUTPUT,FORWARD,POSTROUTING,PREROUTING
。
功能
- filter:实现防火墙一般的数据包过滤功能。(默认表)
- Chain: INPUT,OUTPUT,FORWARD
- nat:网络地址转换。
- Chain: PREROUTING,POSTROUTING
- mangle:修改数据包。
- Chain: INPUT,OUTPUT,FORWARD,POSTROUTING,PREROUTING
- raw:不让 iptables 做数据包链接跟踪,提高性能。
- Chain: PREROUTING,OUTPUT
0x01 简单应用
iptables 有基础的命令还有可选的模块,在 Terminal 中直接可以使用man iptables
查看 iptables 的 man page (Online)。
清除现有 iptables 规则:iptables -F
or iptables --flush
(清除 Chain 中的所有规则,可以加上 -t
or --table
指定某个表,不指定则清除所有)。iptables -X
or iptables --delete-chain
(删除所有用户自定义的 Chain ,即通过 -n
or --new-chain
增加的 Chain )。iptables -Z
or iptables --zero
(清空封包计数器)。
设定默认策略:不符合任何一条规则的时候,按照设定好的默认策略处理,最安全的就是全部 DROP ,再单独添加例外,添加 DROP 的默认策略必须在 Console 下,不然 Terminal 会掉。
iptables -p INPUT DROP
iptables -p OUTPUT DROP
iptables -p FORWARD DROP
-p
or--policy
是为 Chain 添加默认策略。iptables 默认都是 ACCPET 的,如果需要删除此限制,改回 ACCPET 即可。
设置了 DROP 的默认策略之后,必须添加允许回环!
iptables -A INPUT -i lo -p all -j ACCEPT
iptables -A OUTPUT -o lo -p all -j ACCEPT
-i
or--in-interface
是定义入网 NIC 的,表示数据包从何进入,可以使用加号+
作为通配符,比如eth+
表示所有的 eth,也可以用感叹号!
进行排除匹配。
部分版本的 Linux 需要重启 iptables 服务才能生效(server iptables restart
or/etc/init.d/iptables restart
),我使用的是 Debian,现在 Debian 已经是实时生效 iptables 的了,不需要重启服务。也可以使用iptables-save > /home/iptables.rule
导出 iptables 规则,到时候再使用 iptables-restore
恢复。
开启允许通过的端口:如果刚刚上面设置了默认 DROP 策略,现在就要来设置例外规则了,不然任何流量出入都会被丢弃了。现在来开个 SSH(22)端口。
iptables -A INPUT -p tcp --dport 22 -j ACCEPT
iptables -A INPUT -p tcp --sport 22 -j ACCEPT
-A
or--append
新增一条规则,默认是最后一条规则,如果需要插入优先级别更高的可以使用-I
or--insert
。-p
or--protocol
是指定协议,常见协议有:tcp,udp,icmp,igmp
等,可以使用all
匹配所有协议,在协议名称前加感叹号!
表示排除此协议,如!tcp
表示除了 tcp 协议以外的协议。--dport
or--destination-port
是目的端口,限制要访问的目的端口,可以用:
号表示范围,比如1:100
表示 1 - 100 端口。--sport
or--source-port
是来源端口,使用方法和目的端口一致。-j
or--jump
代表了处理动作,常见处理动作有:ACCEPT,REJECT,DROP,REDIRECT,MASQUERADE,LOG,DNAT,SNAT,MIRROR,QUEUE,RETURN,MARK
等,ACCPET 代表放行,REJECT 代表拒绝,DROP 代表丢弃,其他更多的说明请参考 man page。
如果要限制允许访问的 IP 来源地址,可以用 -s
or --src
or --source
来限制。
iptables -A INPUT -s 8.8.8.8 -p tcp --dport 22 -j ACCEPT
iptables -A INPUT -m iprange --src-range 8.8.8.1-8.8.8.10 -p tcp --dport 22 -j ACCEPT
来源地址可以是单个 IP 地址,也可以是地址段
8.8.8.0/24
这种格式,如果要限定范围就需要用-m iprange --src-range
加范围限制,地址也可以使用感叹号!
进行排除匹配。
要开放常用端口,也可以使用 -m multiport --dport
参数。
iptables -A INPUT -m multiport --dport 21,22,80,3306,8000:8999 -p tcp -j ACCPET
禁止 ping:ping 是基于 ICMP 协议的,所以禁掉 ICMP 包就 OK 了。
iptables -A INPUT -p icmp -j DROP
iptables -A OUTPUT -p icmp -j DROP
但是,用这种方式禁用掉 ICMP 协议,服务器就不可以发起 ping 请求,我们可以利用状态防火墙的特性,根据状态来过滤。先删除旧的策略。
iptables -D INPUT -p icmp -j DROP
iptables -D OUTPUT -p icmp -j DROP
-D
or--delete
是用于删除规则,输入完整的策略即可删除。
iptables -A INPUT -p icmp --icmp-type Echo-Request -j DROP
iptables -A INPUT -p icmp --icmp-type Echo-Reply -j ACCEPT
iptables -A INPUT -p icmp --icmp-type destination-Unreachable -j ACCEPT
--icmp-type
是用于定位 ICMP 数据包的类型,可以使用iptables -p icmp --help
查看详细定义或者在 man page 中查看。这里选择 DROP 掉请求,但是允许返回报文通过。
丢弃状态为 INVALID 的 HTTP 数据包:状态为 INVALID 的都是无效的包,直接 DROP。
iptables -A INPUT -m state --state INVALID -j DROP
iptables -A OUTPUT -m state --state INVALID -j DROP
iptables -A FORWARD -m state --state INVALID -j DROP
-m state --state
是用来识别连接状态的,常见的有 4 种状态,NEW,INVALID,ESTABLISHED,RELATED
。
丢弃外网的私网源地址请求:服务器是公网的,没有内网互联机器,源地址是私网地址的基本都是 IP 欺骗,直接 DROP。
iptables -A INPUT -i eth0 -s 10.0.0.0/8 -j DROP
iptables -A INPUT -i eth0 -s 172.16.0.0/12 -j DROP
iptables -A INPUT -i eth0 -s 192.168.0.0/16 -j DROP
0x02 高级应用
防止 DDOS 和 CC 攻击:可以通过 iptables 记录访问过频,然后禁止掉过频密的请求。
iptables -A INPUT -p tcp --dport 80 --syn -m recent --name web_viewer --rcheck --seconds 60 --hitcount 10 -j LOG --log-prefix 'CC_ATTACK:' --log-ip-options
iptables -A INPUT -p tcp --dport 80 --syn -m recent --name web_viewer --rcheck --seconds 60 --hitcount 10 -j DROP
iptables -A INPUT -p tcp --dport 80 --syn -m recent --name web_viewer --set -j ACCEPT
每 60 秒只允许建立 10 个新连接,超出则丢弃。
防止 SSH 爆破:公网服务器总会被人爬到然后爆破 SSH 密码,直接用 iptables 中的 recent 模块将爆破的禁掉。
iptables -A INPUT -p tcp --dport 22 -m recent --name SSH_Brute --rcheck --seconds 300 --hitcount 3 -j DROP
iptables -A INPUT -p tcp --dport 22 -m recent --name SSH_Brute --set -j ACCEPT
这里的流程就是,第一次发出 SSH 连接的时候,会先检查 SSH_Brute 列表中有无记录,并且是否满足 3 次,如果满足则丢弃,生存期是 5 分钟(300 秒),如果是第一次连接,自然不会符合第一条规则,所以就跳到第二条,将当前用户的 IP 添加到 SSH_Brute 表中,并允许此次通过。这样就可以限制了,5 分钟内,只能尝试 3 次,超出这个次数就会被 DROP。
但这样还是存在一个问题,就是每隔5分钟之后还是可以爆破,但我们又不能将时间设置得太长,不然我们自己管理都被 DROP 了请求,所以这里可以用 update
标签来代替 rcheck
标签。两者作用其实大致相同,只是处理流程不一样, rcheck
是从接受到数据包就开始计算时间,但是 update
是从最近的 DROP 数据包开始计算时间的,等于在一定时间内允许你发起 X 次连接,但一旦超出了,就开始 DROP 你的请求一定的时间。这样的过滤更加严格。
iptables -A INPUT -p tcp --dport 22 -m recent --name SSH_Brute --update --seconds 3600 --hitcount 3 -j DROP
iptables -A INPUT -p tcp --dport 22 -m recent --name SSH_Brute --set -j ACCPET
与上面其实就是换成了
update
,作用是一旦发起了超过 3 次连接就禁止一个小时。
- 我的微信
- 这是我的微信扫一扫
-
- 我的微信公众号
- 我的微信公众号扫一扫
-