不攻擊你一下,都不知道你的系統(tǒng)有多脆弱!
當(dāng)今互聯(lián)網(wǎng)行業(yè),特別是初創(chuàng)公司雨后春筍般,大部分公司對安全的重視、投入或者理解都是不足的。
如此導(dǎo)致,沒有事故其樂融融,一旦出事慌慌張張。亡羊補(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ù)器的防火墻策略,正確做法是只開放80和443端口,屏蔽除此之外的其他端口,這就是“白名單”做法。而如果使用“黑名單”,假設(shè)不允許SSH端口對公網(wǎng)開放,那策略可能只把默認(rèn)的22端口放入了黑名單中,萬事大吉了么?實(shí)際情況是,工程師為了偷懶或者圖方便,私自把SSH的監(jiān)聽端口改成了2222,繞過了黑名單策略。懵逼了吧?
** 2 縱深防御原則**
Defense in Depth 也是設(shè)計(jì)安全方案的重要指導(dǎo)思想。就像你不光在HMTL表單上有JS的字段校驗(yàn),服務(wù)端也有校驗(yàn),達(dá)到層層過濾的效果。因?yàn)樵谝粋€環(huán)節(jié)設(shè)置所有的防御措施是不可能的,把風(fēng)險(xiǎn)分散到各個層面進(jìn)行攔截也不失為一種穩(wěn)妥的辦法。
** 3 數(shù)據(jù)與代碼分離原則**
大多數(shù)“注入”引發(fā)的安全問題都是違背了這個原則,比如“SQL注入”就是把不合法的用戶輸入拼接起來進(jìn)行了非法的數(shù)據(jù)庫操作。其他類似XSS, CRLF注入亦同。
** 4 不可預(yù)測原則**
該原則與前面三種不同,更多的是從克服攻擊方法的角度看問題。它就妙在即使無法修復(fù)code來保證安全,我也能夠使攻擊的方法無效,或者只是提高攻擊的門檻,都可以算做成功的防御。
比如論壇的帖子序號假設(shè)是升序自增長的,那么攻擊者想要批量刪除文章,腳本只要簡單的遞增循環(huán)就搞定了。但如果按照“不可預(yù)測”原則,帖子的序號是隨機(jī)的類似uuid的不可預(yù)測值,那必然提高了攻擊者遍歷所有帖子序號的門檻。
強(qiáng)調(diào)字符編碼的一致性真的不僅僅是為了看起來/運(yùn)行起來不亂碼而已 Character Encoding Consistency
編碼問題
現(xiàn)而今互聯(lián)網(wǎng)應(yīng)用普遍會要求研發(fā)環(huán)境所有字符編碼必須是UTF-8(還在用GBK?那是鐵了心不想進(jìn)軍國際)。統(tǒng)一編碼對很多人可能只是意味著:打開IDE不亂碼,前后端數(shù)據(jù)傳輸不亂碼等等。其實(shí)混亂的字母編碼很可能導(dǎo)致安全問題!
在GBK字符集中,0xbf27 不是一個有效的多字節(jié)字符,在解析為單字節(jié)字符的過程中,0xbf27 變成了 0xbf(?) 和 0x27(') 雙字符,0xbf5c 是GBK字符集里有效的中文字符(縗)。
該漏洞早在2006年就被發(fā)現(xiàn),國外用來討論數(shù)據(jù)庫字符集設(shè)為GBK時,在進(jìn)入數(shù)據(jù)庫之前,比如PHP中使用addslashes()函數(shù),或者開啟magic_quotes_gpc時,添加的轉(zhuǎn)義符就會造成的這個注入漏洞。
*http://shiflett.org/blog/2006/jan/addslashes-versus-mysql-real-escape-string *
假設(shè)一張users表,查詢語句是
select * from users
where username = '$input_username'
and password = '$input_password'
攻擊者輸入的密碼是:
0xbf27 or '1'='1
因?yàn)?0xbf27 不是有效字符,經(jīng)過PHP addslashes() 轉(zhuǎn)義后會在 bf 和 27 之間添加轉(zhuǎn)義符 (""的ASCII 碼為 0x5c), 最終變成了0xbf5c27。
而 0xbf5c 正好對應(yīng)GBK字符(縗),所以SQL到數(shù)據(jù)庫里就變成了
select * from users *
where username = '$input_username'
and password = '縗' or '1'='1'
SQL列截?cái)喙?/strong>
在設(shè)計(jì)可變長度列的時候,到底設(shè)置多長很多人是拍腦袋,就算突然哪天發(fā)現(xiàn)長度不夠了,大不了 Alter 加長一下唄。 但是實(shí)際情況是,這里就有漏洞!
MYSQL 里面有個 sql_mode 選項(xiàng),設(shè)置為default時,意味著沒有開啟 STRICT_ALL_TABLES選項(xiàng),用戶插入超長的值只會提示warning, 而不是 error 報(bào)異常。利用這點(diǎn)就可以實(shí)現(xiàn)越權(quán)訪問等攻擊。
WordPress就出現(xiàn)過一個真實(shí)的案例,注冊一個用戶名為“admin (55個空格) x”的用戶,存到數(shù)據(jù)庫的時候被截?cái)嗔耍@樣數(shù)據(jù)庫里就有兩用戶名是 admin 的記錄。當(dāng)然你可以說第二條有空格不會用等式查詢沒問題,但如果出現(xiàn) like 之類的語句呢,誰也不敢保證。
CRLF注入
CR = 回車 (ASCII 13, \r, 0x0d), 本義是光標(biāo)重新回到本行開頭,r的英文return,控制字符可以寫成CR,即Carriage Return。
**LF **= 換行 (ASCII 10, \n, 0x0a), 本義是光標(biāo)往下一行(不一定到下一行行首),n的英文newline,控制字符可以寫成LF,即Line Feed
在計(jì)算機(jī)還沒有出現(xiàn)之前,有一種叫做電傳打字機(jī)(Teletype Model 33)的玩意,每秒鐘可以打10個字符。但是它有一個問題,就是打完一行換行的時候,要用去0.2秒,正好可以打兩個字符。要是在這0.2秒里面,又有新的字符傳過來,那么這個字符將丟失。
于是,研制人員想了個辦法解決這個問題,就是在每行后面加兩個表示結(jié)束的字符。一個叫做“回車”,告訴打字機(jī)把打印頭定位在左邊界;另一個叫做“換行”,告訴打字機(jī)把紙向下移一行。
白帽子中講的第一個場景是日志文件注入,通過換行符可以打印一些偽造的日志,但是實(shí)用性比較弱。另一個危害比較大,是“注入HTTP頭”。
在HTTP協(xié)議中,HTTP頭是通過“\r\n”來分割的,這種CRLF注入也叫“Http Response Splitting”,字面就說明白了,就是把應(yīng)答的 body 給肢解了,攻擊者把自己的代碼注入到肢解后的原本頁面代碼中,達(dá)到攻擊目的。
加密算法攻擊
常見的對稱加密算法分為分組加密算法與流密碼加密算法兩種。
分組加密算法基于“分組”(block)進(jìn)行操作,根據(jù)算法的不同,每個分組的長度可能不同。代表算法有DES, 3-DES, Blowfish, IDEA, AES等。
而流密碼加密算法,則每次只處理一個字節(jié),加密和解密雙方使用相同偽隨機(jī)加密數(shù)據(jù)流,一般都是逐位異或隨機(jī)密碼本的內(nèi)容。代表有 RC4, ORYX, SEAL 等。
** 1 流密碼攻擊**
流密碼加密算法的性能非常好,因此非常受開發(fā)者的環(huán)境。但是在流密碼的使用中,最常見的錯誤便是使用同一個秘鑰進(jìn)行多次加解密。破解流密碼的這種攻擊稱作 “Reused Key Attack”,在這種攻擊下,攻擊者不需要知道秘鑰就可以還原出明文。
基本原理通過簡單的公式推導(dǎo)就可以理解。假設(shè)明文A,和明文B,秘鑰C,那么 **XOR **異或加密可表示為:
E(A) = A xor C
E(B) = B xor C
我們知道密文肯定是公之于眾的,又知道相同的兩個數(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
這個公式四個數(shù)值,意味著只需要知道其中三個,就可以推導(dǎo)出剩下的一個。而公式中完全沒有秘鑰C的存在...
攻擊原理也就清晰了,我先通過合法請求獲取到明文 A 對應(yīng)的密文 E(A),然后拿到另一個用戶的密文 E(B), 可以輕松反推出明文 B 來。
有關(guān)流密碼的攻擊方法還有幾種,諸如 Bit-flipping Attack, 弱隨機(jī) IV 問題,WEP破解等等。總之,這一切都提醒我們,作為開發(fā)者在使用任何一個加密算法的時候,一定要將其原理研究透徹,否則自認(rèn)為的"安全"都可能淪為別人的笑柄。
** 2 ECB模式的缺陷**
分組加密算法,除了算法本身,還有一些通用的加密模式,常見的有:ECB, CBC, CFB, OFB, CTR 等。如果加密模式被攻擊,那么不論加密算法的秘鑰有多長, 都可能不安全。
ECB模式(電碼簿模式)是最簡單的一種加密模式,它的每個分組之間相對獨(dú)立,加密過程如圖:
ECB模式最大的問題也就除非分組的獨(dú)立性上:攻擊者只需對調(diào)任意分組的密文,在經(jīng)過解密后,所得的明文順序也是經(jīng)過對調(diào)的。
來個直觀的例子,很容易理解。假設(shè)某個支付應(yīng)用中,用戶提交的密文對應(yīng)的明文是:
member=abc||pay=10000.00
其中前16個字節(jié)為:
member=abc||pay=
這正好是一個或者兩個分組的長度,因此攻擊者只需要使用“1.00”的密文,替換“10000.00”的密文,就可以偽造支付金額從10000元變成了1元。
注意,ECB模式的缺陷并非是某個加密算法的問題,即使強(qiáng)壯如 AES-256 算法,只要使用ECB模式,也無法避免這問題。因此,當(dāng)需要加密的明文長度大于一個分組的長度是,應(yīng)當(dāng)避免使用ECB模式。
有些同學(xué)會說,以后就用 CBC分組鏈?zhǔn)郊用?/strong>模式,肯定沒問題了。少年,天下沒有無縫的蛋。其實(shí)針對CBC模式的“Padding Oracle Attack” 在2002年就出現(xiàn)了,但是 CBC 確實(shí)比 ECB的攻擊難度要大很多,有興趣的同學(xué)可以研究下。
結(jié)語
互聯(lián)網(wǎng)安全是個很大的話題,白帽子一書中將其劃分成四大部分:世界觀安全、客戶端腳本安全、服務(wù)器端應(yīng)用安全、公司安全運(yùn)營(業(yè)務(wù)安全),身為互聯(lián)網(wǎng)人,
安全防范, 責(zé)無旁貸。