掌握防火牆的工作原理,以及如何設定防火牆來提高 Linux 的安全性
所有人都聽說過防火牆(哪怕僅僅是在網路犯罪片裡看到過相關的情節設定),很多人也知道他們的計算機裡很可能正執行著防火牆,但是很少有人明白在必要的時候如何駕馭防火牆。
防火牆被用來攔截那些不請自來的網路流量,然而不同網路需要的安全級別也不盡相同。比如說,和在外面一家咖啡館裡使用公共 WiFi 相比,你在家裡的時候可以更加信任網路裡的其它計算機和裝置。你或許希望計算機能夠區分可以信任和不可信任的網路,不過最好還是應該學會自己去管理(或者至少是核實)你的安全設定。
網路里不同裝置之間的通訊是通過一種叫做埠的閘道器實現的。這裡的埠指的並不是像 USB 埠 或者 HDMI 埠這樣的物理連線。在網路術語中,埠是一個純粹的虛擬概念,用來表示某種型別的資料到達或離開一台計算機時候所走的路徑。其實也可以換個名字來稱呼,比如叫“連線”或者“門口”,不過 早在 1981 年的時候 它們就被稱作埠了,這個叫法也沿用至今。其實埠這個東西沒有任何特別之處,只是一種用來指代一個可能會發生資料傳輸的地址的方式。
1972 年,發布了一份 埠號列表(那時候的埠被稱為“通訊端”),並且從此演化為一組眾所周知的標準埠號,幫助管理特定型別的網路流量。比如說,你每天存取網站的時候都會使用 80 和 443 埠,因為網際網路上的絕大多數人都同意(或者是預設)資料從 web 伺服器上傳輸的時候是通過這兩個埠的。如果想要驗證這一點,你可以在使用瀏覽器存取網站的時候在 URL 後面加上一個非標準的埠號碼。比如說,存取 example.com:42
的請求會被拒絕,因為 example.com 在 42 埠上並不提供網站服務。
如果你是通過 80 埠存取同一個網站,就可以(不出所料地)正常存取了。你可以在 URL 後面加上 :80
來指定使用 80 埠,不過由於 80 埠是 HTTP 存取的標準埠,所以你的瀏覽器其實已經預設在使用 80 埠了。
當一台計算機(比如說 web 伺服器)準備在指定埠接收網路流量的時候,保持該埠向網路流量開放是一種可以接受的(也是必要的)行為。但是不需要接收流量的埠如果也處在開放狀態就比較危險了,這就是需要用防火牆解決的問題。
有很多種設定防火牆的方式,這篇文章介紹 firewalld。在桌面環境下它被整合在網路管理器裡,在終端裡則是整合在 firewall-cmd
裡。很多 Linux 發行版都預裝了這些工具。如果你的發行版裡沒有,你可以把這篇文章當成是管理防火牆的通用性建議,在你所使用的防火牆軟體裡使用類似的方法,或者你也可以選擇安裝 firewalld
。
比如說在 Ubuntu 上,你必須啟用 universe 軟體倉庫,關閉預設的 ufw
防火牆,然後再安裝 firewalld
:
$ sudo systemctl disable ufw$ sudo add-apt-repository universe$ sudo apt install firewalld
Fedora、CentOS、RHEL、OpenSUSE,以及其它很多發行版預設就包含了 firewalld
。
無論你使用哪個發行版,如果希望防火牆發揮作用,就必須保持它在開啟狀態,並且設定成開機自動載入。你應該盡可能減少在防火牆維護工作上所花費的精力。
$ sudo systemctl enable --now firewalld
或許你每天都會連線到很多不同的網路。在工作的時候使用的是一個網路,在咖啡館裡是另一個,在家裡又是另一個。你的計算機可以判斷出哪一個網路的使用頻率比較高,但是它並不知道哪一個是你信任的網路。
一個防火牆的區域裡包含了埠開放和關閉的預設規則。你可以通過使用區域來選擇一個對當前網路最適用的策略。
你可以開啟網路管理器裡的連線編輯器(可以在應用選單裡找到),或者是使用 nm-connection-editor &
命令以獲取所有可用區域的列表。
在網路連線列表中,雙擊你現在所使用的網路。
在出現的網路設定視窗中,點選“通用”分頁。
在“通用”面板中,點選“防火牆區域”旁邊的下拉式選單以獲取所有可用區域的列表。
也可以使用下面的終端命令以獲取同樣的列表:
$ sudo firewall-cmd --get-zones
每個區域的名稱已經可以透露出設計者建立這個區域的意圖,不過你也可以使用下面這個終端命令獲取任何一個區域的詳細資訊:
$ sudo firewall-cmd --zone work --list-allwork target: default icmp-block-inversion: no interfaces: sources: services: ssh dhcpv6-client ports: protocols: [...]
在這個例子中,work
區域的設定是允許接收 SSH 和 DHCPv6-client 的流量,但是拒絕接收其他任何使用者沒有明確請求的流量。(換句話說,work
區域並不會在你瀏覽網站的時候攔截 HTTP 響應流量,但是 會 攔截一個針對你計算機上 80 埠的 HTTP 請求。)
你可以依次檢視每一個區域,弄清楚它們分別都允許什麼樣的流量。比較常見的有:
work
:這個區域應該在你非常信任的網路上使用。它允許 SSH、DHCPv6 和 mDNS,並且還可以新增更多允許的專案。該區域非常適合作為一個基礎設定,然後在此之上根據日常辦公的需求自定義一個工作環境。public
: 用在你不信任的網路上。這個區域的設定和工作區域是一樣的,但是你不應該再繼續新增其它任何允許專案。drop
: 所有傳入連線都會被丟棄,並且不會有任何響應。在不徹底關閉網路的條件下,這已經是最接近隱形模式的設定了,因為只允許傳出網路連線(不過隨便一個埠掃描器就可以通過傳出流量檢測到你的計算機,所以這個區域並不是一個隱形裝置)。如果你在使用公共 WiFi,這個區域可以說是最安全的選擇;如果你覺得當前的網路比較危險,這個區域也一定是最好的選擇。block
: 所有傳入連線都會被拒絕,但是會返回一個訊息說明所請求的埠被禁用了。只有你主動發起的網路連線是被允許的。這是一個友好版的 drop
區域,因為雖然還是沒有任何一個埠允許傳入流量,但是說明了會拒絕接收任何不是本機主動發起的連線。home
: 在你信任網路裡的其它計算機的情況下使用這個區域。該區域只會允許你所選擇的傳入連線,但是你可以根據需求新增更多的允許專案。internal
: 和工作區域類似,該區域適用於內部網路,你應該在基本信任網路里的計算機的情況下使用。你可以根據需求開放更多的埠和服務,同時保持和工作區域不同的一套規則。trusted
: 接受所有的網路連線。適合在故障排除的情況下或者是在你絕對信任的網路上使用。你可以為你的任何一個網路連線都指定一個區域,並且對於同一個網路的不同連線方式(比如乙太網、WiFi 等等)也可以指定不同的區域。
選擇你想要的區域,點選“儲存”按鈕提交修改。
養成為網路連線指定區域的習慣的最好辦法是從你最常用的網路開始。為你的家庭網路指定家庭區域,為工作網路指定工作區域,為你最喜歡的圖書館或者咖啡館的網路指定公關區域。
一旦你為所有常用的網路都指定了一個區域,在之後加入新的網路的時候(無論是一個新的咖啡館還是你朋友家的網路),試圖也為它指定一個區域吧。這樣可以很好地讓你意識到不同的網路的安全性是不一樣的,你並不會僅僅因為使用了 Linux 而比任何人更加安全。
每次你加入一個新的網路的時候,firewalld
並不會提示你進行選擇,而是會指定一個預設區域。你可以在終端裡輸入下面這個命令來獲取你的預設區域:
$ sudo firewall-cmd --get-defaultpublic
在這個例子裡,預設區域是 public
區域。你應該保證該區域有非常嚴格的限制規則,這樣在將它指定到未知網路中的時候才比較安全。或者你也可以設定你自己的預設區域。
比如說,如果你是一個比較多疑的人,或者需要經常接觸不可信任的網路的話,你可以設定一個非常嚴格的預設區域:
$ sudo firewall-cmd --set-default-zone dropsuccess$ sudo firewall-cmd --get-defaultdrop
這樣一來,任何你新加入的網路都會被指定使用 drop
區域,除非你手動將它制定為另一個沒有這麼嚴格的區域。
Firewalld 的開發者們並不是想讓他們設定的區域能夠適應世界上所有不同的網路和所有級別的信任程度。你可以直接使用這些區域,也可以在它們基礎上進行個性化設定。
你可以根據自己所需要進行的網路活動決定開放或關閉哪些埠,這並不需要對防火牆有多深的理解。
在你的防火牆上新增許可的最簡單的方式就是新增預設服務。嚴格來講,你的防火牆並不懂什麼是“服務”,因為它只知道埠號碼和使用協定的型別。不過在標準和傳統的基礎之上,防火牆可以為你提供一套埠和協定的組合。
比如說,如果你是一個 web 開發者並且希望你的計算機對本地網路開放(這樣你的同事就可以看到你正在搭建的網站了),可以新增 http
和 https
服務。如果你是一名遊戲玩家,並且在為你的遊戲公會執行開源的 murmur 語音聊天伺服器,那麼你可以新增 murmur
服務。還有其它很多可用的服務,你可以使用下面這個命令檢視:
$ sudo firewall-cmd --get-services amanda-client amanda-k5-client bacula bacula-client \ bgp bitcoin bitcoin-rpc ceph cfengine condor-collector \ ctdb dhcp dhcpv6 dhcpv6-client dns elasticsearch \ freeipa-ldap freeipa-ldaps ftp [...]
如果你找到了一個自己需要的服務,可以將它新增到當前的防火牆設定中,比如說:
$ sudo firewall-cmd --add-service murmur
這個命令 在你的預設區域裡 新增了指定服務所需要的所有埠和協定,不過在重新啟動計算機或者防火牆之後就會失效。如果想讓你的修改永久有效,可以使用 --permanent
標誌:
$ sudo firewall-cmd --add-service murmur --permanent
你也可以將這個命令用於一個非預設區域:
$ sudo firewall-cmd --add-service murmur --permanent --zone home
有時候你希望允許的流量並不在 firewalld
定義的服務之中。也許你想在一個非標準的埠上執行一個常規服務,或者就是想隨意開放一個埠。
舉例來說,也許你正在執行開源的 虛擬桌遊 軟體 MapTool。由於 MapTool 伺服器應該使用哪個埠這件事情並沒有一個行業標準,所以你可以自行決定使用哪個埠,然後在防火牆上“開一個洞”,讓它允許該埠上的流量。
實現方式和新增服務差不多:
$ sudo firewall-cmd --add-port 51234/tcp
這個命令 在你的預設區域 裡將 51234 埠向 TCP 傳入連線開放,不過在重新啟動計算機或者防火牆之後就會失效。如果想讓你的修改永久有效,可以使用 --permanent
標誌:
$ sudo firewall-cmd --add-port 51234/tcp --permanent
你也可以將這個命令用於一個非預設區域:
$ sudo firewall-cmd --add-port 51234/tcp --permanent --zone home
在路由器的防火牆上設定允許流量和在本機上設定的方式是不同的。你的路由器可能會為它的內嵌防火牆提供一個不同的設定介面(原理上是相同的),不過這就超出本文範圍了。
如果你不再需要某項服務或者某個埠了,並且設定的時候沒有使用 --permanent
標誌的話,那麼可以通過重新啟動防火牆來清除修改。
如果你已經將修改設定為永久生效了,可以使用 --remove-port
或者 --remove-service
標誌來清除:
$ sudo firewall-cmd --remove-port 51234/tcp --permanent
你可以通過在命令中指定一個區域以將埠或者服務從一個非預設區域中移除。
$ sudo firewall-cmd --remove-service murmur --permanent --zone home
你可以隨意使用 firewalld
預設提供的這些區域,不過也完全可以建立自己的區域。比如如果希望有一個針對遊戲的特別區域,你可以建立一個,然後只有在玩兒遊戲的時候切換到該區域。
如果想要建立一個新的空白區域,你可以建立一個名為 game
的新區域,然後重新載入防火牆規則,這樣你的新區域就啟用了:
$ sudo firewall-cmd --new-zone game --permanentsuccess$ sudo firewall-cmd --reload
一旦建立好並且處於啟用狀態,你就可以通過新增玩遊戲時所需要的服務和埠來實現個性化客製化了。
從今天起開始思考你的防火牆策略吧。不用著急,可以試著慢慢搭建一些合理的預設規則。你也許需要花上一段時間才能習慣於思考防火牆的設定問題,以及弄清楚你使用了哪些網路服務,不過無論是處在什麼樣的環境裡,只要稍加探索你就可以讓自己的 Linux 工作站變得更為強大。