Portknocking 可以用來,當我們需要保護一台公開的伺服器對任意ip公開ssh或ftp等服務埠時,又同時需要對抗惡意人士的tcp port掃瞄或是暴力連接測試。其實後者是多講的,以一位負責的管理者而言,責任內的每一台公開伺服器,他就必需盡最大的能力,將它保護起來,同時又保持對善意人士的開放服務。
這個 Portknocking 觀念,我是上個月才知道的,但就我所看到的網頁資料,它的觀念到少已經出來5年了。我卻很少查到中文網頁有介紹這項觀念與技術。
問題是它在網路安全的防範上,又相當的強固。實在搞不懂為什麼沒有人介紹它。我想原因應該是,知道的人自己看國外網站資料就行了,不需要靠中文網站資料,不知道的人永遠不會知道,所以完全用不著,加上這名詞太生澀,中譯名可能不統一。
ok,回到主題。先介紹觀念:
一言以蔽之,就是芝麻.開門-芝麻.開門技術。瞭解了嗎?不瞭解?好,大陸有很專業的人士,翻譯做「端口碰撞技術」。這麼專業的詞彙,聰明的你就瞭解了吧?
大陸有那麼多看得懂英語的人,卻說不好中文,經常把英文詞彙翻得怪裡怪氣。我想他們看台灣翻的,一樣也覺得怪裡怪氣吧。
哇又離題了。什麼叫芝麻開門?就是當不知道口令的陌生人來到我們家門口時,門神永遠讓它吃閉門羹。但若來人以正確的順序及文字說出:芝麻.開門! 的時候,門就晃郎郎地打開了,金銀財寶隨便你進去拿。
這看過阿里巴巴卡通的小學生都知道,那跟我的網路安全保護有什麼關係?有,當惡意的陌生人,如果做不到芝麻開門的暗號動作時,那我們的重要服務埠(如SSH的 22)就不會對他開放。如果我們在連到真正的重要服務之前,有先設定做一些連線敲門動作(即芝麻開門暗號),讓公開伺服器察覺到,這是主人來了,才自動開22的門,於是我們就可以連進去了。
通常這類芝麻開門的暗號動作,是主人以「先嘗試連65535個埠中某一個埠」,「再嘗試連65535個埠中的另一個埠」,這種類似保險箱的密碼組合,為開門暗號。惡意人士,很難從65535個埠中選2個為組合(高中機率基礎計算 C-6萬5千取2),找出正確的開門暗號。因此它相當強固。若要更強固,我們可以 C-6萬5千取4,就如左圖的說明,要先經過正確的先敲1號門、再敲2號門、再敲3號門,再敲4號門,真正的 n 號蓬門始為君開。這是幾乎不可能被猜出來的埠號組合。
什麼?這不就是搞老式保險箱轉盤號碼鎖嗎?對啊。不過「端口碰撞技術」感覺高深多了,可以讓你的老闆和同事對你肅然起敬,整個FU就是不一樣;要是跟他們說「我使用芝麻開門技術」來保護伺服器,顯得多麼沒有水準呢!(大陸稱為技術含量 呵呵)
接下來介紹轉盤號碼鎖,也就是門神的實作。實作的PK技術有很多。早期 iptables 還沒有強大外掛模組功能時,許多人用 bash 或者是 c 寫了不少服務器來實作這個觀念,例如 Knockd, PortKnockO等等…但載入這些服務器後,總是會多佔系統資源。又因為現在的每一台對外公開服務的 Linux 機器,都必定會使用 iptables 來做基本的防火牆功能,所以我選擇的實作,又是簡單省資源又高效率的 iptables + recent 模組方法。先前已經提過它可以用來阻當高頻率的連線。
以下範例使用新增一個 chain,和設定一些封包檢查與貼標籤的規則,要求以5秒內正確做出連線組合動作,先連168 port,再連978 port,來做為保護SSH 22 port ,的實作說明。
如果你使用檔案: /etc/sysconfig/iptables, 正常方式來儲存 iptables 的設定的話,將下列幾段文字加入該檔案的最後,COMMIT行之前。
如果你使用命令方式/sbin/iptables -A ..如此如此..這般這般…. 直接下的話,要以 iptables -N INTO-PHASE2 新增一個 chain。
:INTO-PHASE2 --A INTO-PHASE2 -m recent --name PHASE1 --remove-A INTO-PHASE2 -m recent --name PHASE2 --set -A INTO-PHASE2 -j LOG --log-prefix "INTO PHASE2: "-A INPUT -m recent --update --name PHASE1 -A INPUT -p tcp --dport 168 -m recent --set --name PHASE1 -A INPUT -p tcp --dport 978 -m recent --rcheck --name PHASE1 -j INTO-PHASE2 -A INPUT -p tcp -s YOUR_HOST_IP --dport 22 -m recent --rcheck --seconds 5 --name PHASE2 -j ACCEPT
每一行的順序不能變,一行一行解釋如下:
第一行:INTO-PHASE2 -
新增一個叫做INTO-PHASE2 的 chain,沒有預設的放行或丟棄等動作。
第二行:把進來INTO-PHASE2 chain裡的封包,除去標籤名為 PHASE1 的封包。
第三行:把進來INTO-PHASE2 chain裡的封包,貼上標籤名為 PHASE2 的封包。
第四行:把進來INTO-PHASE2 chain裡的封包,留下一個系統 syslog 記錄 (本行可要可不要)
第五行:把連線目標埠為168的封包,貼上 PHASE1 的標籤。
第六行:把連線目標埠為978、同時也要有貼著 PHASE1標籤的封包,送到 INTO-PHASE2 處理
===> 也就是被移去 PHASE1標籤、然後被貼上 PHASE2 標籤。
第七行:被貼上 PHASE2 標籤的封包,同時也想連我伺服器 IP 的 22 SSH port 時,讓它通過。
有人可能會問,為什麼要照上面的順序動作設,這要是講到完,眼淚就流不完了。主要的想法是,我們5秒內正確順序連168再接978的一個連線封包會被依次貼上 PHASE1再清除,再被貼上 PHASE2 的標籤,有著 PHASE2 的標籤後,才能通過22 port 。
那 麼我們要如何發出口令暗號?
很多方法,有慢慢一行一行下口令,然後手忙腳亂;也可以寫個小 script,只要用 telnet 或 nmap 之類的網路連線工具,先後快速連168埠再接著馬上連978。然後馬上使用標準的 ssh客戶端來連22,才(就)會通了。
opendoor.sh 示意, opendoor.sh IP 168 978:
#!/bin/bash # $1 host name or IP address telnet $1 $2 &> /dev/null telnet $1 $3 &> /dev/null ssh $1
夢見草
九月 21, 2009 - 5:15 下午1
感謝您的好文分享,我參考你的這篇文章實作成功了。底下是我實作成功的筆記 http://dominic16y.world.edoors.com/C6iVNy67IcS4
ming
九月 21, 2009 - 10:30 下午2
哈哈 謝謝你的更正啊~保護ssh的話,我現在是用「金鑰交換認證ONLY」了。比較懶人,強度也還算夠(當然,得相信客戶端是安全不被入侵的)。
但要保護其它通訊應用,如果是自己寫的AP,或許這個觀念是可以採納的。
starg
十二月 18, 2009 - 3:38 下午3
難得一見的好文
剛好有需要參考到 感激不盡