不攻擊你一下,都不知道你的系統(tǒng)有多脆弱!
當(dāng)今互聯(lián)網(wǎng)行業(yè),特別是初創(chuàng)公司雨后春筍般,大部分公司對(duì)安全的重視、投入或者理解都是不足的。
如此導(dǎo)致,沒(méi)有事故其樂(lè)融融,一旦出事慌慌張張。亡羊補(bǔ)牢不是我們的出路,未雨綢繆,防患未然才是。
最近把道哥的《白帽子講Web安全》重新翻了翻,挑出一些比較容易被忽視的點(diǎn)給大家也給自己刷新一下#安全#觀念。
黑名單是非常不好的設(shè)計(jì)思想
設(shè)計(jì)安全方案
-白帽子兵法
1 Secure By Default 原則
設(shè)計(jì)安全方案的基本原則,中文翻譯“默認(rèn)安全”不太好理解,其實(shí)就包含兩層含義:白名單/黑名單思想,和最小權(quán)限原則。
兩者從字面就比較好理解,這里必須特別強(qiáng)調(diào)一下“盡量更多的使用白名單,少用黑名單”,這樣可以保證安全的范圍可控,權(quán)限最小。
比如制定Web服務(wù)器的防火墻策略,正確做法是只開(kāi)放80和443端口,屏蔽除此之外的其他端口,這就是“白名單”做法。而如果使用“黑名單”,假設(shè)不允許SSH端口對(duì)公網(wǎng)開(kāi)放,那策略可能只把默認(rèn)的22端口放入了黑名單中,萬(wàn)事大吉了么?實(shí)際情況是,工程師為了偷懶或者圖方便,私自把SSH的監(jiān)聽(tīng)端口改成了2222,繞過(guò)了黑名單策略。懵逼了吧?
** 2 縱深防御原則**
Defense in Depth 也是設(shè)計(jì)安全方案的重要指導(dǎo)思想。就像你不光在HMTL表單上有JS的字段校驗(yàn),服務(wù)端也有校驗(yàn),達(dá)到層層過(guò)濾的效果。因?yàn)樵谝粋€(gè)環(huán)節(jié)設(shè)置所有的防御措施是不可能的,把風(fēng)險(xiǎn)分散到各個(gè)層面進(jìn)行攔截也不失為一種穩(wěn)妥的辦法。
** 3 數(shù)據(jù)與代碼分離原則**
大多數(shù)“注入”引發(fā)的安全問(wèn)題都是違背了這個(gè)原則,比如“SQL注入”就是把不合法的用戶輸入拼接起來(lái)進(jìn)行了非法的數(shù)據(jù)庫(kù)操作。其他類似XSS, CRLF注入亦同。
** 4 不可預(yù)測(cè)原則**
該原則與前面三種不同,更多的是從克服攻擊方法的角度看問(wèn)題。它就妙在即使無(wú)法修復(fù)code來(lái)保證安全,我也能夠使攻擊的方法無(wú)效,或者只是提高攻擊的門(mén)檻,都可以算做成功的防御。
比如論壇的帖子序號(hào)假設(shè)是升序自增長(zhǎng)的,那么攻擊者想要批量刪除文章,腳本只要簡(jiǎn)單的遞增循環(huán)就搞定了。但如果按照“不可預(yù)測(cè)”原則,帖子的序號(hào)是隨機(jī)的類似uuid的不可預(yù)測(cè)值,那必然提高了攻擊者遍歷所有帖子序號(hào)的門(mén)檻。
強(qiáng)調(diào)字符編碼的一致性真的不僅僅是為了看起來(lái)/運(yùn)行起來(lái)不亂碼而已 Character Encoding Consistency
編碼問(wèn)題

現(xiàn)而今互聯(lián)網(wǎng)應(yīng)用普遍會(huì)要求研發(fā)環(huán)境所有字符編碼必須是UTF-8(還在用GBK?那是鐵了心不想進(jìn)軍國(guó)際)。統(tǒng)一編碼對(duì)很多人可能只是意味著:打開(kāi)IDE不亂碼,前后端數(shù)據(jù)傳輸不亂碼等等。其實(shí)混亂的字母編碼很可能導(dǎo)致安全問(wèn)題!
在GBK字符集中,0xbf27 不是一個(gè)有效的多字節(jié)字符,在解析為單字節(jié)字符的過(guò)程中,0xbf27 變成了 0xbf(?) 和 0x27(') 雙字符,0xbf5c 是GBK字符集里有效的中文字符(縗)。

該漏洞早在2006年就被發(fā)現(xiàn),國(guó)外用來(lái)討論數(shù)據(jù)庫(kù)字符集設(shè)為GBK時(shí),在進(jìn)入數(shù)據(jù)庫(kù)之前,比如PHP中使用addslashes()函數(shù),或者開(kāi)啟magic_quotes_gpc時(shí),添加的轉(zhuǎn)義符就會(huì)造成的這個(gè)注入漏洞。
*http://shiflett.org/blog/2006/jan/addslashes-versus-mysql-real-escape-string *
假設(shè)一張users表,查詢語(yǔ)句是
select * from users
where username = '$input_username'
and password = '$input_password'
攻擊者輸入的密碼是:
0xbf27 or '1'='1
因?yàn)?0xbf27 不是有效字符,經(jīng)過(guò)PHP addslashes() 轉(zhuǎn)義后會(huì)在 bf 和 27 之間添加轉(zhuǎn)義符 (""的ASCII 碼為 0x5c), 最終變成了0xbf5c27。
而 0xbf5c 正好對(duì)應(yīng)GBK字符(縗),所以SQL到數(shù)據(jù)庫(kù)里就變成了
select * from users *
where username = '$input_username'
and password = '縗' or '1'='1'
SQL列截?cái)喙?/strong>
在設(shè)計(jì)可變長(zhǎng)度列的時(shí)候,到底設(shè)置多長(zhǎng)很多人是拍腦袋,就算突然哪天發(fā)現(xiàn)長(zhǎng)度不夠了,大不了 Alter 加長(zhǎng)一下唄。 但是實(shí)際情況是,這里就有漏洞!
MYSQL 里面有個(gè) sql_mode 選項(xiàng),設(shè)置為default時(shí),意味著沒(méi)有開(kāi)啟 STRICT_ALL_TABLES選項(xiàng),用戶插入超長(zhǎng)的值只會(huì)提示warning, 而不是 error 報(bào)異常。利用這點(diǎn)就可以實(shí)現(xiàn)越權(quán)訪問(wèn)等攻擊。
WordPress就出現(xiàn)過(guò)一個(gè)真實(shí)的案例,注冊(cè)一個(gè)用戶名為“admin (55個(gè)空格) x”的用戶,存到數(shù)據(jù)庫(kù)的時(shí)候被截?cái)嗔耍@樣數(shù)據(jù)庫(kù)里就有兩用戶名是 admin 的記錄。當(dāng)然你可以說(shuō)第二條有空格不會(huì)用等式查詢沒(méi)問(wèn)題,但如果出現(xiàn) like 之類的語(yǔ)句呢,誰(shuí)也不敢保證。
CRLF注入
CR = 回車 (ASCII 13, \r, 0x0d), 本義是光標(biāo)重新回到本行開(kāi)頭,r的英文return,控制字符可以寫(xiě)成CR,即Carriage Return。
**LF **= 換行 (ASCII 10, \n, 0x0a), 本義是光標(biāo)往下一行(不一定到下一行行首),n的英文newline,控制字符可以寫(xiě)成LF,即Line Feed
在計(jì)算機(jī)還沒(méi)有出現(xiàn)之前,有一種叫做電傳打字機(jī)(Teletype Model 33)的玩意,每秒鐘可以打10個(gè)字符。但是它有一個(gè)問(wèn)題,就是打完一行換行的時(shí)候,要用去0.2秒,正好可以打兩個(gè)字符。要是在這0.2秒里面,又有新的字符傳過(guò)來(lái),那么這個(gè)字符將丟失。
于是,研制人員想了個(gè)辦法解決這個(gè)問(wèn)題,就是在每行后面加兩個(gè)表示結(jié)束的字符。一個(gè)叫做“回車”,告訴打字機(jī)把打印頭定位在左邊界;另一個(gè)叫做“換行”,告訴打字機(jī)把紙向下移一行。
白帽子中講的第一個(gè)場(chǎng)景是日志文件注入,通過(guò)換行符可以打印一些偽造的日志,但是實(shí)用性比較弱。另一個(gè)危害比較大,是“注入HTTP頭”。
在HTTP協(xié)議中,HTTP頭是通過(guò)“\r\n”來(lái)分割的,這種CRLF注入也叫“Http Response Splitting”,字面就說(shuō)明白了,就是把應(yīng)答的 body 給肢解了,攻擊者把自己的代碼注入到肢解后的原本頁(yè)面代碼中,達(dá)到攻擊目的。

加密算法攻擊
常見(jiàn)的對(duì)稱加密算法分為分組加密算法與流密碼加密算法兩種。
分組加密算法基于“分組”(block)進(jìn)行操作,根據(jù)算法的不同,每個(gè)分組的長(zhǎng)度可能不同。代表算法有DES, 3-DES, Blowfish, IDEA, AES等。
而流密碼加密算法,則每次只處理一個(gè)字節(jié),加密和解密雙方使用相同偽隨機(jī)加密數(shù)據(jù)流,一般都是逐位異或隨機(jī)密碼本的內(nèi)容。代表有 RC4, ORYX, SEAL 等。
** 1 流密碼攻擊**
流密碼加密算法的性能非常好,因此非常受開(kāi)發(fā)者的環(huán)境。但是在流密碼的使用中,最常見(jiàn)的錯(cuò)誤便是使用同一個(gè)秘鑰進(jìn)行多次加解密。破解流密碼的這種攻擊稱作 “Reused Key Attack”,在這種攻擊下,攻擊者不需要知道秘鑰就可以還原出明文。
基本原理通過(guò)簡(jiǎn)單的公式推導(dǎo)就可以理解。假設(shè)明文A,和明文B,秘鑰C,那么 **XOR **異或加密可表示為:
E(A) = A xor C
E(B) = B xor C
我們知道密文肯定是公之于眾的,又知道相同的兩個(gè)數(shù)字進(jìn)行 XOR 異或運(yùn)算結(jié)果為 0,由此可得:
E(A) xor E(B) = (A xor C) xor (B xor C) = A xor B xor C xor C = A xor B
即:
E(A) xor E(B) = A xor B
這個(gè)公式四個(gè)數(shù)值,意味著只需要知道其中三個(gè),就可以推導(dǎo)出剩下的一個(gè)。而公式中完全沒(méi)有秘鑰C的存在...
攻擊原理也就清晰了,我先通過(guò)合法請(qǐng)求獲取到明文 A 對(duì)應(yīng)的密文 E(A),然后拿到另一個(gè)用戶的密文 E(B), 可以輕松反推出明文 B 來(lái)。
有關(guān)流密碼的攻擊方法還有幾種,諸如 Bit-flipping Attack, 弱隨機(jī) IV 問(wèn)題,WEP破解等等。總之,這一切都提醒我們,作為開(kāi)發(fā)者在使用任何一個(gè)加密算法的時(shí)候,一定要將其原理研究透徹,否則自認(rèn)為的"安全"都可能淪為別人的笑柄。
** 2 ECB模式的缺陷**
分組加密算法,除了算法本身,還有一些通用的加密模式,常見(jiàn)的有:ECB, CBC, CFB, OFB, CTR 等。如果加密模式被攻擊,那么不論加密算法的秘鑰有多長(zhǎng), 都可能不安全。
ECB模式(電碼簿模式)是最簡(jiǎn)單的一種加密模式,它的每個(gè)分組之間相對(duì)獨(dú)立,加密過(guò)程如圖:

ECB模式最大的問(wèn)題也就除非分組的獨(dú)立性上:攻擊者只需對(duì)調(diào)任意分組的密文,在經(jīng)過(guò)解密后,所得的明文順序也是經(jīng)過(guò)對(duì)調(diào)的。
來(lái)個(gè)直觀的例子,很容易理解。假設(shè)某個(gè)支付應(yīng)用中,用戶提交的密文對(duì)應(yīng)的明文是:
member=abc||pay=10000.00
其中前16個(gè)字節(jié)為:
member=abc||pay=
這正好是一個(gè)或者兩個(gè)分組的長(zhǎng)度,因此攻擊者只需要使用“1.00”的密文,替換“10000.00”的密文,就可以偽造支付金額從10000元變成了1元。
注意,ECB模式的缺陷并非是某個(gè)加密算法的問(wèn)題,即使強(qiáng)壯如 AES-256 算法,只要使用ECB模式,也無(wú)法避免這問(wèn)題。因此,當(dāng)需要加密的明文長(zhǎng)度大于一個(gè)分組的長(zhǎng)度是,應(yīng)當(dāng)避免使用ECB模式。
有些同學(xué)會(huì)說(shuō),以后就用 CBC分組鏈?zhǔn)郊用?/strong>模式,肯定沒(méi)問(wèn)題了。少年,天下沒(méi)有無(wú)縫的蛋。其實(shí)針對(duì)CBC模式的“Padding Oracle Attack” 在2002年就出現(xiàn)了,但是 CBC 確實(shí)比 ECB的攻擊難度要大很多,有興趣的同學(xué)可以研究下。

結(jié)語(yǔ)
互聯(lián)網(wǎng)安全是個(gè)很大的話題,白帽子一書(shū)中將其劃分成四大部分:世界觀安全、客戶端腳本安全、服務(wù)器端應(yīng)用安全、公司安全運(yùn)營(yíng)(業(yè)務(wù)安全),身為互聯(lián)網(wǎng)人,
安全防范, 責(zé)無(wú)旁貸。