天天看點

Linux安全之iptables自定義鍊

作者:郭主任講網絡

iptables 是運作在使用者空間的應用軟體,通過控制 Linux 核心 netfilter 子產品,來管理網絡資料包的處理和轉發。在大部分 Linux 發行版中,可以通過手冊頁 或 man iptables 擷取使用者手冊。通常 iptables 需要核心子產品支援才能運作,此處相應的核心子產品通常是 Xtables。

Linux安全之iptables自定義鍊

Linux安全之iptables自定義鍊

【1】自定義鍊的原因

【2】使用者自定義鍊的設計

【3】使用者自定義鍊建立

【4】使用者自定義鍊重命名

【5】使用者自定義鍊删除

【6】實戰示範

Linux安全之iptables自定義鍊

Linux安全之iptables自定義鍊

  • 【1】自定義鍊的原因

之前,我們一直在使用的都是 iptables 預設鍊中定義規則,所有我們也可以自定義鍊。

當預設鍊中的規則非常多時,不友善我們管理。

想象一下,如果 INPUT鍊中存放了 200 條規則,這 200 條規則有針對 httpd 服務的,有針對 sshd 服務的,有針對私網 IP 的,有針對公網 IP 的。假如,我們突然想要修改針對 httpd 服務的相關規則,難道我們還要從頭看一遍這 200 條規則,找出哪些規則是針對 httpd 的嗎?這顯然不合理。

是以,iptables 中可以自定義鍊,通過自定義鍊即可解決上述問題。

  • 【2】使用者自定義鍊的設計

假設,我們自定義一條鍊,鍊名叫 IN_WEB。我們可以将所有針對 80 端口的入站規則都寫入到這條自定義鍊中,當以後想要修改針對 Web 服務的入站規則時,就直接修改 IN_WEB 鍊中的規則就好了。即使預設鍊中有再多的規則,我們也不會害怕了,因為我們知道,所有針對 80 端口的入站規則都存放在 IN_WEB 鍊中。

同理,我們可以将針對 sshd 的出站規則放入到 OUT_SSH 自定義鍊中,将針對 Nginx 的入站規則放入到 IN_NGINX 自定義鍊中,這樣,我們就能想改哪裡改哪裡,再也不同擔心找不到規則在哪裡了。

但是需要注意的是,自定義鍊并不能直接使用,而是需要被預設鍊引用才能夠使用。

  • 【3】使用者自定義鍊建立
# 清空防火牆
$ sudo iptables -t filter -F

# 建立一個自定義鍊為IN_WEB
$ sudo iptables -t filter -N IN_WEB

# 可以看到自定義的IN_WEB鍊
$ sudo iptables -t filter -nvL
Chain IN_WEB (0 references)
pkts    bytes    target    prot    opt    in    out    source    destination
......           

自定義鍊建立完成後,檢視 filter 表中的鍊。發現自定義鍊已經被建立,而且這條自定義鍊的引用計數為 0 (0 references),也就是說,這條自定義鍊還沒有被任何預設鍊所引用。是以,即使 IN_WEB 中配置了規則,也不會生效。

自定義鍊已經建立完畢,現在我們就可以直接在自定義鍊中配置規則了。

# 對自定義鍊的操作與對預設鍊的操作基本一緻
$ sudo iptables -I IN_WEB -s 192.168.31.139 -j REJECT
$ sudo iptables -t filter -I IN_WEB -s 192.168.31.140 -j REJECT

# 兩者操作基本一緻
$ sudo iptables -t filter -nvL
Chain IN_WEB (0 references)
pkts bytes target    prot opt in    out    source              destination
    0    0 REJECT    all  --  *      *      192.168.31.140      0.0.0.0/0          reject-with icmp-port-unreachable
    0    0 REJECT    all  --  *      *      192.168.31.139      0.0.0.0/0          reject-with icmp-port-unreachable
......           

自定義鍊中已經有了一些規則,但是現在這些規則無法比對到任何封包,因為我們并沒有在任何預設鍊中引用它。既然 IN_WEB 鍊是為了針對 Web 服務的入站規則而建立的,那麼這些規則應該去比對入站的封包,是以我們應該用 INPUT 鍊去引用它。

當然,自定義鍊在哪裡建立,應該被哪條預設鍊引用,取決于實際的工作場景,因為此處示例的規則是比對入站封包,是以在 INPUT 鍊中引用自定義鍊。

# 定義引用規則,使用-j指定自定義鍊
# 在INPUT鍊中添加了一條規則,通路本機80端口的tcp封包将會被這條規則比對到IN_WEB鍊
$ sudo iptables -t filter -I INPUT -p tcp --dport 80 -j IN_WEB
           
# 檢視定義的引用規則
$ sudo iptables -t filter -nvL
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target    prot opt in    out    source              destination
    0    0 IN_WEB    tcp  --  *      *      0.0.0.0/0            0.0.0.0/0          tcp dpt:80

Chain IN_WEB (1 references)
pkts bytes target    prot opt in    out    source              destination
    0    0 REJECT    all  --  *      *      192.168.31.140      0.0.0.0/0          reject-with icmp-port-unreachable
    0    0 REJECT    all  --  *      *      192.168.31.139      0.0.0.0/0          reject-with icmp-port-unreachable
......           

我們使用 -j 選項指定動作,而此處,我們将動作替換為了自定義鍊。當 -j 對應的值為一個自定義鍊時,就表示被目前規則比對到的封包将交由對應的自定義鍊處理,具體怎樣處理取決于自定義鍊中的規則。

當 IN_WEB 自定義鍊被 INPUT 鍊引用以後,可以發現,IN_WEB 鍊的引用計數已經變為 1,表示這條自定義鍊已經被引用了 1 次,自定義鍊還可以引用其他的自定義鍊。

那麼此刻,我們在 192.168.31.140 上嘗試通路本機的 80 端口,已經被拒絕通路,證明剛才自定義鍊中的規則已經生效了。

  • 【4】使用者自定義鍊重命名

過了一段時間,我們發現 IN_WEB 這個名字不太合适,我們想要将這條自定義鍊重命名,把名字改成 WEB。

# 自定義鍊重命名
$ sudo iptables -t filter -E IN_WEB WEB
           
# 檢視定義的引用規則
$ sudo iptables -t filter -nvL
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target    prot opt in    out    source              destination
    0    0 WEB        tcp  --  *      *      0.0.0.0/0            0.0.0.0/0          tcp dpt:80

Chain WEB (1 references)
pkts bytes target    prot opt in    out    source              destination
    0    0 REJECT    all  --  *      *      192.168.31.140      0.0.0.0/0          reject-with icmp-port-unreachable
    0    0 REJECT    all  --  *      *      192.168.31.139      0.0.0.0/0          reject-with icmp-port-unreachable
           
  • 【5】使用者自定義鍊删除

好了,我們已經能夠建立自定義了,那麼怎樣删除自定義鍊呢?可以使用 iptables 的 -X 選項可以删除自定義鍊。

但是删除自定義鍊時,需要滿足兩個條件:

  • 1、自定義鍊沒有被任何預設鍊引用,即自定義鍊的引用計數為 0。
  • 2、自定義鍊中沒有任何規則,即自定義鍊為空。
# (1) 删除引用自定義鍊的規則
$ sudo iptables -t filter -D INPUT 1

# (2) 需要清空對應的自定義鍊
$ sudo iptables -t filter -F WEB

# (3) 删除自定義鍊
$ sudo iptables -t filter -X WEB
           
  • 【6】實戰示範
# 清空nat鍊的規則
$ sudo iptables -t nat -F

# 建立自定義鍊
$ sudo iptables -N clean_in

# 限制icmp協定的廣播ping
$ sudo iptables -A clean_in -d 255.255.255.255 -p icmp -j DROP
$ sudo iptables -A clean_in -d 172.16.255.255 -p icmp -j DROP

# 禁止非法包
$ sudo iptables -A clean_in -p tcp ! --syn -m state --state NEW -j DROP
$ sudo iptables -A clean_in -p tcp --tcp-flags ALL ALL -j DROP
$ sudo iptables -A clean_in -p tcp --tcp-flags ALL NONE -j DROP
           
#(1)如果是外網通路本地位址172.16.100.7則交給自定義鍊clean_in處理
$ sudo iptables -A INPUT -d 172.16.100.7 -j clean_in

#(2)如果自定義鍊沒有一條比對上,則return回去;自定義鍊傳回
$ sudo iptables -A clean_in -d 172.16.100.7 -j RETURN

#(3)本地回環接口都允許
$ sudo iptables -A INPUT  -i lo -j ACCEPT
$ sudo iptables -A OUTPUT -o lo -j ACCEPT

#(4)禁止端口
$ sudo iptables -A INPUT  -i eth0 -m multiport -p tcp --dports 53,113,135,137,139,445 -j DROP
$ sudo iptables -A INPUT  -i eth0 -m multiport -p udp --dports 53,113,135,137,139,445 -j DROP
$ sudo iptables -A INPUT  -i eth0 -p udp --dport 1026 -j DROP
$ sudo iptables -A INPUT  -i eth0 -m multiport -p tcp --dports 1433,4899 -j DROP

# icmp速率限制
$ sudo iptables -A INPUT  -p icmp -m limit --limit 10/second -j ACCEPT