如果拖庫無法避免,但加密就安全么?

就在2011年上半年,我們還是站在旁觀者的立場(chǎng)討論這些事情。但隨即我們就遭遇了CSDN、多玩和天涯等等的數(shù)據(jù)泄露,其中最為敏感的,一方面是用戶信息,另一個(gè)當(dāng)然就是用戶口令。由于身份實(shí)名、口令通用等情況影響,一時(shí)間人人自危。各個(gè)站點(diǎn)也陷在口水當(dāng)中。

但實(shí)際上根據(jù)推斷,這些入侵都是一些過去時(shí),也就是說這些庫早就在地下流傳。同時(shí)流出,也許就是一個(gè)集體性的心理效應(yīng)。

這種針對(duì)數(shù)據(jù)庫記錄的竊取,被一些攻擊者稱為“拖庫”,于是有了一個(gè)自然而諧音的戲稱“脫褲”。只是攻擊者日趨不厚道,從前只是偷了人家的褲子,現(xiàn)在還要晾在大街上,并貼上布告說,“看,丫褲子上還有補(bǔ)丁呢”。

如果拖庫是很難避免的,那么采用合理的加密策略,讓攻擊者拿到庫后的影響降低到更小就是必要的。

明文存放口令的時(shí)代肯定是要結(jié)束了,但加密就安全么?

明文的密碼固然是不能接受的,但錯(cuò)誤的加密策略同樣很糟糕。讓我們看看下列情況。

簡(jiǎn)單使用標(biāo)準(zhǔn)HASH

我想起了一個(gè)90年代黑客笑話,有人進(jìn)入一臺(tái)UNIX主機(jī),抓到了一個(gè)shadow文檔,但破解不了。于是,他用自己的機(jī)器做了一個(gè)假的現(xiàn)場(chǎng),故意留下這個(gè)shadow,最后看看別人用什么口令來試,最后再用這些口令與滲透原來的主機(jī)。遺憾的是,那時(shí)我們都把這個(gè)當(dāng)成一個(gè)Joke,充其量回復(fù)一句“I服了you!”,而沒有反思使用標(biāo)準(zhǔn)算法的問題。

目前來看,在口令保存上,使用最為廣泛的算法是標(biāo)準(zhǔn)MD5HASH。但實(shí)際上,很長(zhǎng)時(shí)間,我們都忽略了HASH設(shè)計(jì)的初衷并不是用來加密,而是用來驗(yàn)證。系統(tǒng)設(shè)計(jì)者是因?yàn)镠ASH算法具有不可逆的特點(diǎn)所以“借”用其保存密碼的。但其不可逆的前提假設(shè),是明文集合是無限大的。但放到口令并不一樣,口令的長(zhǎng)度是受限的,同時(shí)其可使用的字符也是受限的。我們可以把口令的總數(shù)看正一個(gè)事實(shí)上的有限集(很難想象有人用100個(gè)字符作為口令)。

比如一個(gè)人的密碼是“123456”,那么任何采用標(biāo)準(zhǔn)MD5加密的網(wǎng)站數(shù)據(jù)庫中,其存放的都是這樣一個(gè)MD5值:E10ADC3949BA59ABBE56E057F20F883E

由于密文均相同,加之HASH算法是單向的,因此攻擊者較早使用的方法就是“密文比對(duì)+高頻統(tǒng)計(jì)”后生成密文字典來攻擊,由于絕大多數(shù)網(wǎng)站和系統(tǒng)的加密實(shí)現(xiàn),都是相同明文口令生成相同的密文,因此,那些有高頻密文的用戶就可能是使用高頻明文口令的用戶。攻擊者一方面可以針對(duì)標(biāo)準(zhǔn)算法來制定高頻明文的對(duì)應(yīng)密文檔來查詢,另一方面,對(duì)于那些非標(biāo)準(zhǔn)算法,高頻統(tǒng)計(jì)攻擊的方法也非常常見。

但查表攻擊迅速壓倒高頻統(tǒng)計(jì)的原因,正是從2000年開始陸續(xù)有網(wǎng)站規(guī)模性明文口令泄漏事件開始的。在過去每一次明文的密碼泄漏事件,攻擊者都會(huì)把使用MD5、SHA1等常見HASH算法加工成的口令與那些采用HASH值來保存的庫進(jìn)行應(yīng)對(duì)。

隨著超算資源的廉價(jià)、GPU的普及、存儲(chǔ)能力的增長(zhǎng),一個(gè)不容忽視的威脅開始躍上桌面,那就是,這些巨大的HASH表已經(jīng)不僅僅是基于泄漏的密碼和常見字符串字典來制作,很多攻擊者通過長(zhǎng)期的分工協(xié)作,通過窮舉的方式來制作一定位數(shù)以下的數(shù)字字母組合的口令串與多種算法加密結(jié)果的映射結(jié)果集,這些結(jié)果集從百GB到幾十TB,這就是傳說中的彩虹表。

HASH的單向性優(yōu)勢(shì)在此已經(jīng)只有理論意義,因?yàn)镠ASH的單向性是靠算法設(shè)計(jì)保證的,使用一個(gè)有限集來表示一個(gè)無限集,其必然是不可逆的。但攻擊者是從查表來完成從HASH到口令明文的還原的。因此其算法的單向性也就失去了意義。

聯(lián)合使用HASH

一些人誤以為,HASH不夠安全是因?yàn)镠ASH算法的強(qiáng)度問題,因此把MD5或者SHA1聯(lián)合使用,其實(shí)這是毫無價(jià)值的(只是徒耗了存儲(chǔ)資源)。如上面所說,HASH的不安全性在于大量口令與其HASH值的對(duì)應(yīng)關(guān)系早已經(jīng)被制作成彩虹表。只要你聯(lián)合使用HASH的算法其中之一在彩虹表中,自然就可以查到了。

同理,那種采用“MD5的頭+SHA的尾”之類的,或者采用其他的混合兩個(gè)值的方法,也一樣是沒有意義的。因?yàn)楣粽呖梢院苋菀椎挠^察到這種組合方法的規(guī)律,經(jīng)過拆解后繼續(xù)按照查表法破解。

自己設(shè)計(jì)算法

我一向認(rèn)為,既然我們不是一個(gè)密碼學(xué)家,而是工程師、程序員,那么放著現(xiàn)成的好東西不用,自己開發(fā)加密算法是相當(dāng)愚蠢的事情。我相信很多程序員都遇到過挖空心思想到了一個(gè)“新算法”,然后發(fā)現(xiàn)早在某篇20世紀(jì)80年代的數(shù)學(xué)論文里,早就提出了相關(guān)算法的情況。

況且在開源時(shí)代,很多算法不僅被實(shí)現(xiàn)和發(fā)布了,而且還經(jīng)歷了長(zhǎng)期的使用推敲。這些都是自己設(shè)計(jì)、自己實(shí)現(xiàn)無法比擬的。

關(guān)于自主設(shè)計(jì)的算法的不安全性,有一個(gè)事情深達(dá)我腦海。記得我在證券系統(tǒng)工作時(shí),由于剛剛接手收購(gòu)來的營(yíng)業(yè)部,需要把一個(gè)clipper編譯的柜臺(tái)系統(tǒng)進(jìn)行遷移,但原來的開發(fā)商已經(jīng)聯(lián)系不到了,當(dāng)時(shí)我們制定了兩條路,一位高手李老師負(fù)責(zé),進(jìn)行數(shù)據(jù)破解,看看是否能還原明文,而我則負(fù)責(zé)破解算法,如果李老師那邊走不通,則我需要解出算法,把000000~999999之間的數(shù)字全部加密,然后用密文做碰撞(那時(shí)證券都是柜臺(tái)操作,沒有網(wǎng)上炒股,密碼都是柜臺(tái)用數(shù)字鍵盤輸入的)。

由于原來的開發(fā)者加了一點(diǎn)花活,我這邊還沒有眉目,那邊旁觀李老師的工程師,已經(jīng)發(fā)出了驚嘆之聲,我跑過去,只見李老師根據(jù)構(gòu)造的幾個(gè)密碼的加密結(jié)果,在紙上匯出了長(zhǎng)得非常像楊輝三角的東西。不到半個(gè)小時(shí),李老師已經(jīng)連解密程序一起做好了。

上面故事的目的是說明,自己設(shè)計(jì)算法無論怎么自我感覺良好,看看美國(guó)官方遴選算法的PK過程大家就明白了,我們無法和全球數(shù)學(xué)家的智慧組合對(duì)抗。

因此自己設(shè)計(jì)實(shí)現(xiàn)算法,并不是一個(gè)好主意。這其中也包括,在實(shí)現(xiàn)上會(huì)不會(huì)有類似輸入超長(zhǎng)字符串會(huì)溢出一類的Bug。

單獨(dú)使用對(duì)稱算法

在標(biāo)準(zhǔn)HASH安全破滅后,又看到有人呼吁用AES,其實(shí)這不是一個(gè)好建議。AES這些對(duì)稱算法,都不具備單向性。網(wǎng)站被攻擊的情況是復(fù)雜的,有的是只有數(shù)據(jù)庫被拖,有的則整個(gè)環(huán)境淪陷。而后者AES密鑰一旦被拿到,密碼就會(huì)被還原出來,這比被查表還要壞。

當(dāng)然我們還看到一種把AES當(dāng)HASH用的思想,就是只保留一部分的AES加密結(jié)果,只驗(yàn)證不還原。但其實(shí)這樣的AES并不見得比HASH有優(yōu)勢(shì)。比如即使攻擊者沒有拿到密鑰,也只拖了庫,但攻擊者自己在拖庫之前注冊(cè)了足夠多的帳號(hào),并使用大量不同的短口令。那么就拿到了一組短明文和對(duì)應(yīng)密文。而此時(shí)密鑰是完全有可能被分析出來的。

而使用DES、AES一類的算法,還是使用標(biāo)注HASH,還是自己設(shè)計(jì)算法,如果不解決不同用戶相同口令密文相同的統(tǒng)計(jì)性缺陷,那么攻擊者即使拿不到密鑰,也都可以先把一些高頻口令用于帳號(hào)注冊(cè),拖庫后進(jìn)行密文比對(duì)。就可以鎖定大量的采用常見口令的用戶。

加“一粒鹽”

其實(shí)很多同仁都指出了哈希加鹽法(HASH+SALT),是問題的解決之道,所謂加鹽(SALT)其實(shí)很簡(jiǎn)單,就是在生成HASH時(shí)給予一個(gè)擾動(dòng),使HASH值與標(biāo)準(zhǔn)的HASH結(jié)果不同,這樣就可以抗彩虹查表了。

比如說,用戶的密碼是123456,加一個(gè)鹽,也就是隨機(jī)字符串“1cd73466fdc24040b5”,兩者合到一起,計(jì)算MD5,得到的結(jié)果是6c9055e7cc9b1bd9b48475aaab59358e。通過這種操作,即便用戶用的弱密碼,也通過加鹽,使實(shí)際計(jì)算哈希值的是一個(gè)長(zhǎng)字符串,一定程度上防御了窮舉攻擊和彩虹表攻擊。

但從我們審計(jì)過的實(shí)現(xiàn)來看,很多人只加了“一粒鹽”。也就是說,對(duì)同一個(gè)站點(diǎn),不同用戶使用同一個(gè)密碼,其密文還是相同的。這就又回到了會(huì)遭遇高頻統(tǒng)計(jì)攻擊,預(yù)先注冊(cè)攻擊等問題。

口令的安全策略

在傳統(tǒng)密碼學(xué)家眼中只有一種加密是理想的,那就是“一次一密”,當(dāng)然事實(shí)上這是不可能的。但如果我們套用這種詞法,我們也可以說,口令安全策略的理想境界,我們可以稱為單向、一人一密、一站一密。

單向:標(biāo)準(zhǔn)HASH算法的價(jià)值盡管在這個(gè)場(chǎng)景下,已經(jīng)被推倒,但其單向性的思想依然是正確的,口令只要是能還原的,就意味著攻擊者也能做到這一點(diǎn),從而失去了意義,因此使用單向算法是必須的。