Linux

調試 iptables 和常見的防火牆陷阱?

  • February 25, 2021

這是一個關於理解和調試 Linux 系統上的軟體防火牆的 規範 問題。

為了回應 EEAA 的回答和 @Shog 的評論,我們需要一個合適的規範問答來結束關於 iptables 的常見相對簡單的問題。

什麼是調試 Linux 軟體防火牆問題的結構化方法,netfilter數據包過濾框架,通常被使用者空間介面iptables所指?

什麼是常見的陷阱、反復出現的問題以及簡單或稍微模糊的事情,以檢查偶爾的防火牆管理員可能會忽略或以其他方式受益於了解?

即使您使用UFWFirewallD (aka firewall-cmd)、Shorewall或類似工具,您也可能會受益於在沒有這些工具提供的抽象層的情況下查看引擎蓋。

這個問題不打算作為建構防火牆的方法:檢查產品文件,例如為iptables Trips & Tricks提供食譜或搜尋標記的iptables ufw firewalld firewall-cmd問題以獲取現有的常見且廣受好評的高分問答。

一般來說:

查看和修改防火牆配置需要管理員權限 ( root),在受限埠號範圍內打開服務也是如此。這意味著您應該以 root 身份登錄root或使用sudo以 root 身份執行命令。我會嘗試用可選的[sudo].

內容:

  1. -I訂單事項或和之間的區別-A
  2. 顯示目前防火牆配置
  3. 解釋輸出iptables -L -v -n
  4. 了解您的環境
  5. INPUT 和 FORWARD 鏈
  6. 核心模組

-I1. 訂單事項或和之間的區別-A

要記住的是防火牆規則是按照它們列出的順序進行檢查的。當觸發允許或禁止數據包或連接的規則時,核心將停止處理鏈。

我認為 新手防火牆管理員最常見的錯誤是他們按照正確的說明打開新埠,例如以下:

[sudo] iptables -A INPUT -i eth0 -p tcp --dport 8080 -j ACCEPT

然後發現它不會生效。

原因是該-A選項在所有現有規則之後添加了該新規則, 並且由於現有防火牆中的最終規則通常是阻止所有未明確允許的流量的規則,從而導致

...
7    2515K  327M REJECT     all  --  *      *       0.0.0.0/0            0.0.0.0/0           reject-with icmp-host-prohibited
8        0  0    ACCEPT     all  --  *      *       0.0.0.0/0            0.0.0.0/0           tcp dpt:8080

或 iptables-save 中的等價物:

...
iptables -A INPUT  -j REJECT
iptables -A INPUT  -p tcp --dport 8080 -j ACCEPT

並且永遠不會達到打開 TCP 埠 8080 的新規則。(正如頑固地保持在 0 個數據包和 0 個字節的計數器所證明的那樣)。

通過插入帶有-I新規則的規則將是鏈中的第一個並且將起作用。

2.顯示目前防火牆配置

我對防火牆管理員的建議是查看 Linux 核心執行的實際配置,而不是嘗試通過使用者友好的工具診斷防火牆問題。通常,一旦您了解了潛在問題,您就可以在這些工具支持的問題中輕鬆解決它們。

命令[sudo] iptables -L -v -n是你的朋友(雖然有些人iptables-save更喜歡)。--line-numbers通常在討論配置時,使用該選項以及編號行很有用。參考規則#X 使討論它們變得更容易一些。

注意: NAT 規則包含在iptables-save輸出中,但必須通過添加選項單獨列出,-t nat[sudo] iptables -L -v -n -t nat --line-numbers.

多次執行該命令並檢查遞增計數器可能是查看新規則是否實際觸發的有用工具。

[root@host ~]# iptables -L -v -n
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
num   pkts bytes target     prot opt in     out     source               destination
1     784K   65M fail2ban-SSH  tcp  --  *      *       0.0.0.0/0            0.0.0.0/0           tcp dpt:22
2    2789K  866M ACCEPT     all  --  *      *       0.0.0.0/0            0.0.0.0/0           state RELATED,ESTABLISHED
3       15  1384 ACCEPT     all  --  lo     *       0.0.0.0/0            0.0.0.0/0
4    44295 2346K ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0           state NEW tcp dpt:22
5    40120 2370K ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0           state NEW tcp dpt:80
6    16409  688K ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0           state NEW tcp dpt:443
7    2515K  327M REJECT     all  --  *      *       0.0.0.0/0            0.0.0.0/0           reject-with icmp-host-prohibited

Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
num   pkts bytes target     prot opt in     out     source               destination
1        0     0 REJECT     all  --  *      *       0.0.0.0/0            0.0.0.0/0           reject-with icmp-host-prohibited

Chain OUTPUT (policy ACCEPT 25 packets, 1634 bytes)
num   pkts bytes target     prot opt in     out     source               destination

Chain fail2ban-SSH (1 references)
num   pkts bytes target     prot opt in     out     source               destination
1        0     0 REJECT     all  --  *      *       117.239.37.150       0.0.0.0/0           reject-with icmp-port-unreachable
2        4   412 REJECT     all  --  *      *       117.253.208.237      0.0.0.0/0           reject-with icmp-port-unreachable

或者,輸出iptables-save給出了一個可以重新生成上述防火牆配置的腳本:

[root@host ~]# iptables-save
*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [441:59938]
:fail2ban-SSH - [0:0]
-A INPUT -p tcp -m tcp --dport 22 -j fail2ban-SSH
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 80 -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 443 -j ACCEPT
-A INPUT -j REJECT --reject-with icmp-host-prohibited
-A FORWARD -j REJECT --reject-with icmp-host-prohibited
-A fail2ban-SSH -s 117.239.37.150/32 -j REJECT --reject-with icmp-port-unreachable
-A fail2ban-SSH -s 117.253.208.237/32 -j REJECT --reject-with icmp-port-unreachable
COMMIT

這是一個偏好問題,您會發現更容易理解。

  1. 解釋輸出iptables -L -v -n ==========================

當沒有明確的規則匹配時,**策略設置鏈使用的預設操作。**在INPUT設置為接受所有流量的鏈中。

INPUT 鏈中的第一條規則立即成為一個有趣的規則,它將所有流量(源 0.0.0.0/0 和目標 0.0.0.0/0)發送到 TCP 埠 22 ( tcp dpt:22) SSH 的預設埠到自定義目標 ( fail2ban-SSH) . 顧名思義,此規則由 fail2ban(一種安全產品,除其他外掃描系統日誌文件以查找可能的濫用行為並阻止濫用者的 IP 地址)維護。

該規則將由類似於iptables -I INPUT -p tcp -m tcp --dport 22 -j fail2ban-SSH或在 iptables-save as 的輸出中找到的 iptables 命令行創建-A INPUT -p tcp -m tcp --dport 22 -j fail2ban-SSH。通常你會在文件中找到這些符號中的任何一個。

計數器指示此規則已匹配 784'000 個數據包和 65 兆字節的數據。

然後,與第一條規則匹配的流量由fail2ban-SSH鏈處理,作為非標準鏈,列在 OUTPUT 鏈下方。

該鏈包含兩條規則,一條針對每個被阻止(帶有 )的濫用者(源 IP 地址 117.253.221.166 或 58.218.211.166 reject-with icm-port-unreachable)。

-A fail2ban-SSH -s 117.253.221.166/32 -j REJECT --reject-with icmp-port-unreachable
-A fail2ban-SSH -s 58.218.211.166/32 -j REJECT --reject-with icmp-port-unreachable

來自那些被阻止主機的 SSH 數據包既不允許也不不允許,現在自定義鏈已完成,將根據 INPUT 鏈中的第二條規則進行檢查。

所有不是發往埠 22 的數據包都通過了 INPUT 鏈中的第一條規則,並且也將在 INPUT 規則 #2 中進行評估。

INPUT 規則編號 2 意味著這是一個有狀態的防火牆,它跟踪連接。這有一些優點,只有新連接的數據包需要根據完整的規則集進行檢查,但是一旦允許,屬於已建立或相關連接的其他數據包將被接受,而無需進一步檢查。

輸入規則 #2 匹配所有打開的和相關的連接,匹配該規則的數據包不需要進一步評估。

**注意:**狀態防火牆配置中的規則更改只會影響新連接,不會影響已建立的連接。

相反,一個簡單的數據包過濾器根據完整的規則集測試每個數據包,而不跟踪連接狀態。在這樣的防火牆中,不會使用狀態關鍵字。

INPUT 規則#3 很無聊,所有連接到環回(lo或 127.0.0.1)介面的流量都是允許的。

INPUT 規則 4、5 和 6 用於通過授予對新連接的訪問權限來打開 TCP 埠 22、80 和 443(分別為 SSH、HTTP 和 HTTPS 的預設埠)(現有連接已被 INPUT 規則 2 允許)。

在無狀態防火牆中,這些規則會在沒有狀態屬性的情況下出現:

4    44295 2346K ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0
5    40120 2370K ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0
6    16409  688K ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0

或者

-A INPUT -p tcp -m tcp --dport 22 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 80 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 443 -j ACCEPT

最後的 INPUT 規則 #7 是阻止在 INPUT 規則 1-7 中未授予訪問權限的所有流量的規則。一個相當普遍的約定:所有不允許的都被拒絕。理論上,可以通過將預設 POLICY 設置為 REJECT 來省略此規則。

始終調查整個鏈條。

4.了解你的環境

4.1 . 軟體防火牆中的設置不會影響網路中其他地方維護的安全設置,即儘管使用iptables路由器上未修改的訪問控制列表打開網路服務或網路中的其他防火牆可能仍會阻止流量…

4.2 . 當沒有服務正在偵聽時,無論防火牆設置如何,您都將無法連接並收到連接被拒絕錯誤。所以:

  • 確認服務正在偵聽(在正確的網路介面/IP 地址上)並使用您期望的埠號[sudo] netstat -plnut或使用ss -tnlp.
  • 如果您的服務尚未執行,請使案例如 netcat 模擬一個簡單的偵聽器:[sudo] nc -l -p 123或者openssl s_server -accept 1234 [options] 如果您需要一個 TLS/SSL 偵聽器(檢查man s_server選項)。
  • 驗證您是否可以從伺服器本身進行連接,即telnet <IP of Server> 123echo "Hello" | nc <IP of Server> 123在測試 TLS/SSL 安全服務openssl s_client -connect <IP of Server>:1234時,然後再從遠端主機嘗試相同的操作。

4.3 . 了解您的服務使用的協議。您無法正確啟用/禁用您不太了解的服務。例如:

  • 使用 TCP 或 UDP 還是兩者都使用(與 DNS 一樣)?
  • 服務是否使用固定的預設埠(例如網路伺服器的 TCP 埠 80)?
  • 或者是否選擇了一個可以變化的動態埠號(即 RPC 服務,如向 Portmap 註冊的經典 NFS)?
  • 臭名昭著的 FTP 甚至使用兩個埠,當配置為使用被動模式時,一個固定埠號和一個動態埠號……
  • 中的服務、埠和協議描述/etc/services不一定與使用埠的實際服務相匹配。

4.4 . 核心數據包過濾器並不是唯一可能限製網路連接的東西:

  • SELinux 也可能會限製網路服務。getenforce將確認 SELinux 是否正在執行。
  • 儘管變得有點晦澀難懂,TCP Wrappers 仍然是加強網路安全的強大工具。檢查ldd /path/to/service |grep libwrap/hosts.[allow|deny]控製文件。

5.INPUTFORWARD鏈條

這裡更徹底地解釋了鏈的概念,但它的短處是:

該**INPUT**鍊是您在發出 iptables 命令的主機上為本地執行的服務打開和/或關閉網路埠的地方。

當**FORWARD**您的 Linux 機器充當網橋、路由器、管理程序和/或網路地址時,您可以應用規則來過濾由核心轉發到其他系統、實際系統以及 Docker 容器和虛擬客戶伺服器伺服器的流量翻譯和埠轉發。

一個常見的誤解是,由於 docker 容器或 KVM 來賓在本地執行,因此應用的過濾規則應該在 INPUT 鏈中,但通常情況並非如此。

6.核心模組

由於包過濾器在 Linux 核心中執行,它也可以編譯為動態模組,實際上是多個模組。大多數發行版都包含 netfilter 作為模組,所需的 netfilter 模組將根據需要載入到核心中,但對於某些模組,防火牆管理員需要手動確保它們被載入。這主要涉及連接跟踪模組,例如nf_conntrack_ftp可以載入insmod.

目前載入到執行核心中的模組可以用lsmod.

確保模組在重新啟動後持續載入的方法取決於 Linux 發行版。

引用自:https://serverfault.com/questions/696182