對(duì)于斗膽開(kāi)始玩vps的文科生來(lái)講,iptables簡(jiǎn)直是地獄中的地獄。有幾家vps供應(yīng)商系統(tǒng)默認(rèn)是帶著些iptables規(guī)則的,以前我一向是難言之隱,一清了之。
我很早就知道這東西重要,但看著太難了,后來(lái)看到log里越來(lái)越多的攻擊記錄,心想這東西得必須學(xué)了,說(shuō)不定哪天哪個(gè)龜孫子就攻進(jìn)來(lái)了。網(wǎng)上及電子書(shū)中的教程一般對(duì)于文科生來(lái)講比較難看懂,有的還畫(huà)著圖,號(hào)稱a picture can tell a thousand words. 但有圖也看不懂,你說(shuō)畫(huà)個(gè)桌子,我知道英語(yǔ)是table、日語(yǔ)稱雞雞。但這個(gè)根本不存在的table,你畫(huà)出來(lái),對(duì)于連看懂火車時(shí)刻表都表示有困難的我,我會(huì)更糊涂的。
說(shuō)閑話少說(shuō)的時(shí)候,實(shí)際上是說(shuō)了很多閑話….咬咬牙開(kāi)始吧,我還是要不怕困難,寫一個(gè)連文科生都能看懂的iptables心得!
如其名稱所示,iptables,就是里面有好幾個(gè)table,大約有過(guò)濾桌、nat桌、mangle桌啥的。后兩個(gè)你先別管,等我搞明白了再來(lái)教你,第一個(gè)桌子從名稱上一看就明白了,過(guò)濾數(shù)據(jù)用的,它也正是我們用來(lái)防止攻擊用的——把壞人過(guò)濾掉,不讓他進(jìn)來(lái)!那我們就講這個(gè)過(guò)濾桌吧。
這個(gè)桌子上放有一條一條的chain,就是鏈子。每個(gè)鏈子由尺子(rules)組成…嚴(yán)肅點(diǎn),我不開(kāi)玩笑了,這么說(shuō)吧,table(表)由chain(鏈)組成,Chain又有規(guī)則組成(rules)。
既然我們只講 filter table(過(guò)濾表),那么table這個(gè)概念就跟我們無(wú)關(guān)了,重點(diǎn)要理解“鏈”和組成“鏈”的“rule (規(guī)則)”。
鏈(chain)與規(guī)則 (rules)
filter table里面有三個(gè)默認(rèn)的鏈,INPUT,OUTPUT 和 FORWARD。FORWARD呢對(duì)于做站基本用不上,我們就講INPUT 和 OUTPUT。因?yàn)槭莿e人要攻擊我們,對(duì)于我們的服務(wù)器來(lái)講,攻擊是要進(jìn)來(lái)的,即INPUT,誒?那么說(shuō)把 INPUT這個(gè)鏈搞明白,就可以防守了?差不多吧。那我們就只講 INPUT好了,越簡(jiǎn)單越好,關(guān)鍵是把概念理清楚,別的細(xì)節(jié),都可以查到的的親。另外,INPUT, OUTPUT, FORWARD都是由規(guī)則組成的鏈,INPUT搞懂了,其他的也就不難了。
平常我們看到iptables,就是一條條的規(guī)則,例如:
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
看到INPUT這個(gè)詞了吧?這說(shuō)明這條規(guī)則屬于INPUT這個(gè)鏈的,tcp是協(xié)議,網(wǎng)站都是用tcp的, –dport 80,就是80這個(gè)端口,也就是別人打開(kāi)你的網(wǎng)站的時(shí)候需要與你的服務(wù)器的80端口連起來(lái),就像一條打印機(jī)線把電腦的打印機(jī)口與打印機(jī)連起來(lái)一樣,不過(guò)網(wǎng)絡(luò)上端口是虛擬的,但實(shí)際工作的時(shí)候是一回事,就是通信。對(duì)于INPUT(發(fā)進(jìn)來(lái))的數(shù)據(jù)包,80是目標(biāo)端口,即destination port, 簡(jiǎn)稱 dport。
因?yàn)槟愕姆?wù)器上放了你的網(wǎng)站,你需要允許別人向80端口發(fā)連接請(qǐng)求,ACCEPT,即接受請(qǐng)求和連接。現(xiàn)在你明白了吧?有了這句,別人就可以連接你的服務(wù)器,打開(kāi)上面的網(wǎng)頁(yè)了。
前面那個(gè)“-A”的意思append,與后面的INPUT連用的,就是把這條規(guī)則加到INPUT這個(gè)鏈的最后面。當(dāng)然現(xiàn)我們INPUT這個(gè)鏈上啥都沒(méi)有,加到最后面,也就是第一條了。
命令行的規(guī)則你大概明白了吧,“-”符號(hào),后面直接跟的是參數(shù)名,參數(shù)名后跟空格,空格后跟這個(gè)參數(shù)的值(姑且這么理解吧)。例如 -p tcp ,這里的‘-p’是不能隨便寫的,是iptables程序定義的,你寫個(gè)“-p”,程序就知道后面跟的是協(xié)議名稱。你寫個(gè)“-A”,iptables程序就知道后面跟的是鏈的名稱。那么“–dport”里的兩個(gè)減號(hào)“–”是啥意思呢?它的功能跟一個(gè)減號(hào)是一樣的,都表示后面是參數(shù)名,不過(guò)兩個(gè)減號(hào)后面跟的參數(shù)名的全稱,一個(gè)減號(hào)跟的是簡(jiǎn)稱,全稱容易看懂,減稱寫起來(lái)省勁。例如上面這句規(guī)則也可以寫成:
iptables -append INPUT --proto tcp --dport 80 --jump ACCEPT
當(dāng)然,愛(ài)裝逼的理科生一般是不會(huì)寫全稱的,大都用一個(gè)減號(hào),一個(gè)字母的簡(jiǎn)稱。
親愛(ài)的windows用戶,注意這里的參數(shù)名和參數(shù)值都是大小寫敏感的,把“-p”寫成“-P”,程序是不工作的。另外英語(yǔ)很好的你可以注意到了,即使是加了兩個(gè)減號(hào)的“全稱”,也不全,proto明明不對(duì),該是protocol才對(duì)。你知道他們理科生語(yǔ)文不好,原諒他們吧。
光有這條還不夠,因?yàn)槟愕膙ps上還有別的服務(wù),例如你上傳文件需要ftp或sftp,進(jìn)入后臺(tái)需要ssh,ftp的默認(rèn)端口是21,ssh是22,我們把它們也加上。
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
iptables -A INPUT -p tcp --dport 21 -j ACCEPT
iptables -A INPUT -p tcp --dport 22 -j ACCEPT
好了,你準(zhǔn)備就開(kāi)放這么多服務(wù),最后在加一句
iptables -A INPUT -j DROP
它的意思是拒絕所有連接…這怎么行?不是說(shuō)要允許80,21,和22嗎?這是因?yàn)镮NPUT是個(gè)鏈子,有頭有尾,按順序來(lái)的。如果有人連接你的80口,第一句規(guī)則說(shuō)ACCEPT,進(jìn)來(lái)吧。那么他發(fā)來(lái)的一梭子彈彈就不再經(jīng)過(guò)后面的規(guī)則了,當(dāng)然也就不會(huì)被放在最后面的DROP這句拒絕了。
現(xiàn)在我們的全部規(guī)則是:
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
iptables -A INPUT -p tcp --dport 21 -j ACCEPT
iptables -A INPUT -p tcp --dport 22 -j ACCEPT
iptables -A INPUT -j DROP
翻譯成文科生的語(yǔ)言就是發(fā)到80(嘴巴),21(菊花),22(貓貓)三個(gè)口的數(shù)據(jù)將接受,想往別的地方塞數(shù)據(jù),一律拒絕。復(fù)習(xí)一下開(kāi)始說(shuō)的,這些東東的意思是在INPUT這個(gè)鏈子上有四條規(guī)則,規(guī)則是按順序一個(gè)一個(gè)來(lái)的,發(fā)來(lái)的數(shù)據(jù)被匹配后,就跳出鏈子,后面的規(guī)則就不再執(zhí)行了。如果你把iptables -A INPUT -j DROP這條放在鏈頭,你的vps就變成了石女,唯有通過(guò)服務(wù)商的面板重啟了!
REJECT 和 DROP
剛才-j 后面的拒絕操作是DROP,正確的英語(yǔ)譯文該是”REJECT”才對(duì)。是的,寫成”-j REJECT”也是可以的。不同之處是REJECT比較客氣,等于告訴想搞你的人“對(duì)不起,人家這兩天不方便。”而DROP就是一聲不坑地拒絕。對(duì)于入侵者,不用那么客氣,用DROP好了。因?yàn)槿绻慊貞?yīng)了,等于告訴想搞你的人你是在線的,只是拒絕了,反而會(huì)引起他繼續(xù)努力的斗志。
狀態(tài) (state)匹配
如果你喜顛顛地拿著上面幾條去試驗(yàn)了,估計(jì)你的vps上的一些網(wǎng)站可能就竿屁了,iptables這個(gè)妹妹很難對(duì)付的。要想讓你的服務(wù)器正常工作,還需要添加這一句在DROP那一句之前。
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
“-m”是“匹配”的意思,-m state的意思是匹配數(shù)據(jù)包狀態(tài),用戶發(fā)來(lái)的數(shù)據(jù)包分別帶有不同的狀態(tài),即 NEW, ESTABLISHED, 和 RELATED。NEW 就是開(kāi)頭搭訕,ESTABLISHED,就是搭訕完了之后后續(xù)的數(shù)據(jù)包,RELATED就是與已經(jīng)存在的連接相關(guān)的數(shù)據(jù)包。總之這句話的意思是,接受已經(jīng)建立了連接的數(shù)據(jù)包,即搭訕之后的數(shù)據(jù)包。現(xiàn)在我們的INPUT鏈?zhǔn)沁@個(gè)樣子的:
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
iptables -A INPUT -p tcp --dport 21 -j ACCEPT
iptables -A INPUT -p tcp --dport 22 -j ACCEPT
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A INPUT -j DROP
意思是外面接受發(fā)往本機(jī)80,21,22的tcp數(shù)據(jù)包,還接受發(fā)往任何端口的已建立(established)和相關(guān)(related)的數(shù)據(jù)包(第四句),剩下的INPUT數(shù)據(jù)包一律拋棄。
為毛要允許狀態(tài)ESTABLISHED 和 RELATED的入站數(shù)據(jù)呢?因?yàn)槟愕姆?wù)器同時(shí)也是臺(tái)電腦,還要從別的服務(wù)器下載東西。下載時(shí),你的服務(wù)器先向別的服務(wù)器發(fā)出連接請(qǐng)求(new),別的服務(wù)器允許你連接,連接建立(ESTABLISHED)之后,就需要接受別的服務(wù)器發(fā)來(lái)的數(shù)據(jù),對(duì)于你的服務(wù)器來(lái)講屬于INPUT。也就是說(shuō),如果沒(méi)有iptables -A INPUT -m state –state ESTABLISHED,RELATED -j ACCEPT這句,wget curl啥的就都不工作了。有了這句,加上前三句,即允許別的電腦連接(new)你的80,21和22端口,同時(shí)允許別的服務(wù)器在你的服務(wù)器先向它發(fā)請(qǐng)求的條件下向你發(fā)送數(shù)據(jù)。另外這些狀態(tài)都是基于tcp協(xié)議來(lái)講的(謝謝BOYPT)。
-A(–append)和-I (–insert)
剛才說(shuō)了,-A INPUT的意思是把一條規(guī)則加在現(xiàn)有INPUT這個(gè)鏈子的最后面,那么寫成-I INPUT,就是把一條規(guī)則強(qiáng)行插入到最前面。如果你比較變態(tài),剛才的INPUT鏈倒著寫也是可以的:
iptables -I INPUT -j DROP
iptables -I INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -I INPUT -p tcp --dport 22 -j ACCEPT
iptables -I INPUT -p tcp --dport 21 -j ACCEPT
iptables -I INPUT -p tcp --dport 80 -j ACCEPT
即后面一條總會(huì)插到現(xiàn)有INPUT鏈的最前面,最終形成的INPUT鏈跟前面是一樣的。
不過(guò),不要試!因?yàn)槟阃ǔJ沁h(yuǎn)程操作你的vps的,你在命令行輸入第一句,立馬掉線!后面就全輸不進(jìn)去了!
–insert也是有用的,例如前面這個(gè)INPUT鏈已經(jīng)起了作用,你想在不清空現(xiàn)有INPUT鏈的基礎(chǔ)上再開(kāi)放一個(gè)端口,例如443。那么就必須寫成
iptables -I INPUT -p tcp --dport 443 -j ACCEPT
如果你寫成 -A,那么這條規(guī)則就被跟在DROP那句后面,發(fā)到443的數(shù)據(jù)在來(lái)到新加的這句之前,就被干掉了。
如果你不想加到最前面,也可以在INPUT后面寫個(gè)數(shù)字,表示添加的位置,如果把一條規(guī)則看成一行,也就是指定所謂的行號(hào)了。把上面添加443端口的規(guī)則寫成:
iptables -I INPUT 3 -p tcp --dport 443 -j ACCEPT
那么就把它放在了第三條規(guī)則(即第三行)的位置了。在命令行里輸入 iptables -nvx -L INPUT (查看現(xiàn)在生效的INPUT鏈),你會(huì)發(fā)現(xiàn)新增加的這條規(guī)則在21端口那句的后面。
把上面的規(guī)則保存到文件里,運(yùn)行一下,你的服務(wù)器就安全多了。
iptables --flush
iptables --delete-chain
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
iptables -A INPUT -p tcp --dport 21 -j ACCEPT
iptables -A INPUT -p tcp --dport 22 -j ACCEPT
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A INPUT -j DROP
關(guān)于iptables的其他內(nèi)容,如記錄日志、屏蔽IP、建立自定義鏈……,日后再說(shuō)吧!無(wú)論如何,搞懂今天講的概念是最重要的,其他的細(xì)節(jié)都可以查到的,總是粘貼別人寫好的規(guī)則,但一直啥也不懂,不是我們的文科生應(yīng)該做的。
思考題:應(yīng)用以上規(guī)則之后,服務(wù)器運(yùn)行正常,但你無(wú)法在家ping你的服務(wù)器了!這是什么呢?