0
安全hash函數(shù)在信息系統(tǒng)中有相當(dāng)廣泛的應(yīng)用,特別是用于消息簽名來保護消息的完整性和不可抵賴性等任務(wù),可以說安全hash函數(shù)是現(xiàn)代應(yīng)用密碼學(xué)最重要的基石之一。如果安全hash函數(shù)出現(xiàn)安全問題,那么整個應(yīng)用密碼體系乃至整個互聯(lián)網(wǎng)的安全都受到嚴(yán)重影響,包括軟件發(fā)行、網(wǎng)絡(luò)支付、設(shè)備升級等等。安全hash函數(shù)面臨的最大技術(shù)安全威脅是同謀碰撞攻擊,但我們也發(fā)現(xiàn)國內(nèi)不少廠家的自制協(xié)議中存在著大量不正確的安全hash應(yīng)用,導(dǎo)致可以利用簡單的方法攻破其防護。近些年隨著計算機性能的提高,針對
MD5、SHA1 函數(shù)的碰撞攻擊研究也進展迅速。而國內(nèi)由于現(xiàn)實情況,替換MD5/SHA1的代價高昂,很難在短期內(nèi)能解決。MD5/SHA1
碰撞究竟會對現(xiàn)有的信息系統(tǒng)產(chǎn)生哪些威脅?本文對 MD5/SHA1
的碰撞攻擊及其應(yīng)用場景進行討論,給出了具體的攻擊實例,同時給出了緩解措施。我們指出,在進行嚴(yán)格的約束消除同謀碰撞的條件下,要攻破MD5/SHA1依然是一個非常艱巨的任務(wù)。盡管如此,這樣的機制只是給了廠商難得的喘息時間,我們依然督促各廠商盡快升級到更安全的HMAC-SHA256。
密碼學(xué)中的安全 hash 函數(shù)與普通的 hash 函數(shù)有著相當(dāng)大的區(qū)別。在典型數(shù)據(jù)結(jié)構(gòu)hash_map、hash_set中所用到的hash函數(shù),只需要將key映射為一個索引即可,即使產(chǎn)生了碰撞,也可以采用開散列或者閉散列的方式進行處理。密碼學(xué)中的安全hash函數(shù)[1]要求則嚴(yán)格的多,至少需要滿足三個性質(zhì):(1)抗碰撞攻擊(2)抗原根攻擊以及(3)抗第二原根攻擊??古鲎补羰侵?,尋找兩個不同的串x和y,使得hash(x)=hash(y)是困難的??乖羰侵?,在hash(x)=s中,已知s,求x是困難的??沟诙羰侵福阎猦ash(x)=s,求一個異于x的串y,使得hash(y)=s是困難的。只有滿足了以上三點的hash函數(shù)才有資格成為安全hash函數(shù)。
MD5/SHA1是用途非常廣泛的安全hash函數(shù)。他們的輸入是任意串,輸出是128/160bit長的散列值。MD5和SHA1在1992年和1993年被發(fā)明出來,在相當(dāng)長一段時間內(nèi),他們被認為是安全的。2004年和2005年,研究者發(fā)現(xiàn)了對他們的攻擊方法,減少了特定情況下發(fā)現(xiàn)碰撞的計算代價。在2007年首次提出了利用MD5碰撞偽造CA證書的理論方法,2008年這種攻擊方法得到了驗證,攻擊者成功偽造了合法的CA證書。而針對SHA1的攻擊方法則一直停留在理論中,直到2017年初,對SHA1的成功碰撞攻擊才首次公開出來。
這里簡要描述MD5的計算過程,以便讀者理解。SHA1的計算過程十分相似:
首先,加入補位,使之bit長度模512的余數(shù)為448(512-64)。接下來將長度表示為小端序,附在后面(大于64bit只取低64bit)。此時bit長度是512的倍數(shù)。接下來依次處理每個512bit的塊。在處理過程中不斷更新MD5的內(nèi)部狀態(tài)(128bit)。在處理完所有的塊后,將其內(nèi)部狀態(tài)輸出,作為最后的散列值。
在某些情況下,攻擊者需要構(gòu)造一個串y使得hash(y)為一指定的值s。此時攻擊者只能控制y,那么此時若要尋求一個滿足hash(y)=s的實例,則屬于原根攻擊。對MD5/SHA1的原根攻擊目前尚無好的計算方法,只能依賴彩虹表、字典或蠻力搜索,攻擊復(fù)雜度相當(dāng)高(MD5的狀態(tài)空間是2^128,蠻力搜索要計算2^128次MD5)。
在另外一些情況下,攻擊者可以同時控制兩個輸入串x和y,使得hash(x)=hash(y),從而欺騙基于hash的驗證系統(tǒng)。這種情況我們稱為“同謀碰撞”。同謀碰撞是可以使用“生日攻擊”大幅度減少運算量的。以MD5為例,借用生日攻擊,我們不需要枚舉所有128bit的串計算MD5值以求碰撞,只需要計算2^64次MD5值即可有50%的幾率找到這樣的x和y。
MD5/SHA1碰撞具有添加后綴依然碰撞的性質(zhì):
若hash(A)=hash(B),則hash(A+S)=hash(B+S)
但是并不滿足增加前綴的性質(zhì),即
hash(A)=hash(B)推不出hash(S+A)=hash(S+B)
由碰撞的后綴延伸特性導(dǎo)致的一種簡單易行的攻擊是長度擴展攻擊(Length Extension Attack) [4]。例如,某些基于MD5的協(xié)議使用了如下形式的簽名值
sign =hash(secret + message)
其中的secret是密鑰。在計算出簽名值sign后,客戶端將sign和message一起提交給服務(wù)端。在某些情況下,攻擊者可以同時獲得簽名值sign和明文message,并且擁有在明文尾部附加任意串的能力。此時,攻擊者可以直接利用MD5的性質(zhì),在明文尾部附加惡意部分s,并直接從原MD5值計算
sign' =hash(sign, s) = hash(secret + message + s)
這樣構(gòu)造出來的新請求message+s擁有合法的簽名sign',因此是能夠通過MD5簽名校驗的,但是包括了攻擊者注入的惡意部分s。這種攻擊在某些CTF題目中也有涉及 [5]。在某些情況下長度擴展攻擊可以用于繞過基于MD5的身份認證 [6]。由于SHA1或者其他的安全Hash大部分具有這樣的性質(zhì),所以將MD5調(diào)換為SHA1或其他安全Hash也大都是無效的。
所有可能被長度擴展攻擊的數(shù)字簽名協(xié)議應(yīng)該立即升級成第四節(jié)中所述的HMAC-SHA256算法,因為有很大可能黑產(chǎn)已經(jīng)在享用你的服務(wù)了。
對于MD5/SHA1更復(fù)雜的攻擊目前主要有共同前綴碰撞攻擊(Identical PrefixCollision)和選擇前綴碰撞攻擊(Chosen Prefix Collision)。共同前綴攻擊是構(gòu)造兩個不同的消息s1和s2,他們由相同的前綴,和不同的尾部“碰撞塊”組成。前幾天震驚世界的SHAttered攻擊是對SHA1進行的共同前綴攻擊。選擇前綴攻擊則是構(gòu)造兩個不同的消息s1和s2,他們不必有共同的前綴,但是經(jīng)過在尾部附加不同的“碰撞塊”后,兩個消息的散列值相同。選擇前綴攻擊是包括共同前綴攻擊的,因此共同前綴的攻擊代價小于選擇前綴攻擊。在Marc Stevens(SHAttered作者)2009年的文章中對此類攻擊的計算代價總結(jié)如表1。
表1:MD5和SHA1的兩種不同攻擊的計算代價
這里的單位是需要計算的hash的次數(shù)。例如2004年之前,對MD5的平凡攻擊(生日攻擊)需要蠻力計算2的64次方次md5 hash。在2009年時,對于MD5的共同前綴攻擊計算代價是2的16次方次MD5 hash,對SHA1的則是2的52次方。不難看出,無論是共同前綴攻擊,還是選擇前綴攻擊,都可以被應(yīng)用在同謀碰撞攻擊中。由于共同前綴攻擊和選擇前綴攻擊的研究進展迅速,同謀碰撞攻擊逐漸成為數(shù)字簽名體系最大的威脅。
計算復(fù)雜度和最后構(gòu)造出的碰撞結(jié)構(gòu)有很大關(guān)系。對于共同前綴碰撞攻擊,由王小云教授提出的攻擊方法需要構(gòu)造兩個碰撞塊,第一個碰撞塊由生日攻擊得到,目的是使得計算完第一碰撞塊后的hash內(nèi)部狀態(tài)的差分滿足特定形式。第二個碰撞塊則由對差分路徑的搜索得到。因此構(gòu)造共同前綴碰撞攻擊只需要兩個碰撞塊。對于選擇前綴碰撞攻擊,需要構(gòu)造多個(>=2個)碰撞塊。第一個碰撞塊的作用相同,后續(xù)的碰撞塊則對第一個碰撞塊計算完成之后內(nèi)部狀態(tài)的區(qū)別做逐一修正。在唯一一份公開的選擇前綴碰撞代碼 [2,3] 中,這個后續(xù)碰撞塊的長度指定為9,意為需要構(gòu)造9次修正塊,以完成一次碰撞攻擊。長度越短,對于每個碰撞塊的要求就越高,計算所需的時間也指數(shù)級提高。在長度為9時,計算可以在普通計算機上運算幾小時即可完成。
對于MD5碰撞的研究主要關(guān)注與快速發(fā)現(xiàn)MD5碰撞。王小云教授的著名工作[7]等,以及謝濤的后續(xù)工作[8]等,使得在短時間內(nèi)構(gòu)造簡短的MD5碰撞成為可能。對SHA1最著名的攻擊是最近的SHA1 Shattered攻擊,是一種共同前綴碰撞攻擊 [9]。另一方面,利用選擇前綴攻擊,可以偽造X509格式的CA證書 [10],以及構(gòu)造多個消息的碰撞“Herding Attack”,可以用于“預(yù)測”任何一次的美國總統(tǒng)大選結(jié)果。 此外,對于攻擊簽名機制,還有一些由于簽名機制實現(xiàn)不當(dāng)而產(chǎn)生的漏洞和對應(yīng)的攻擊方法。下面我們簡要介紹一下選擇前綴碰撞攻擊的能力,然后再討論如何利用擇前綴碰撞攻擊,最后回顧一下對于基于hash的簽名機制實現(xiàn)不當(dāng)而產(chǎn)生的攻擊。
對于兩個給定的不同前綴p1和p2,CPC攻擊可以構(gòu)造出兩個后綴m1和m2,使得
hash(p1+m1) = hash(p2+m2)
而且p1+m1的長度和p2+m2的長度相等。
舉個例子,令p1=“希拉里會當(dāng)選”,p2=“川普會當(dāng)選”。在大選之前先利用CPC攻擊,構(gòu)造出兩個后綴m1和m2,然后計算他們的MD5值v=MD5(p1+m1)=MD5(p2+m2)。然后告訴世人本次大選結(jié)果的md5值是v。在真正結(jié)果揭曉后,若希拉里當(dāng)選,則展示p1+m1,否則展示p2+m2,即可完成預(yù)測。當(dāng)然實際場景下沒有那么簡單,任何人看到“XXX當(dāng)選”后面那串毫無意義的后綴字串都會產(chǎn)生質(zhì)疑。在實際攻擊場景中往往需要一個可以在末尾附加額外數(shù)據(jù)的數(shù)據(jù)結(jié)構(gòu)上進行CPC攻擊,例如PE可執(zhí)行文件、ZIP壓縮文件、JPG圖像文件等末尾都可以加入后綴且不影響正常使用。
利用CPC攻擊,還可以構(gòu)造多個消息的碰撞。以三個消息為例(圖片來自[9]):
IHV0是MD5默認的初始狀態(tài)。m1/m2/m3是三個不同的前綴,經(jīng)過MD5運算后得到了三個不同的MD5狀態(tài)(值)IHV1、IHV2、IHV3。此時先用CPC攻擊m1和m2,生成padding c1和c2,他們有共同的MD5值IHV4。此時對m3做平凡的補長p3,生成IHV5。再從IHV4和IHV5開始使用CPC攻擊,即可得到c4和c5。此時
MD5(m1+c1+c4)=MD5(m2+c2+c4)=MD5(m3+p3+c5)
而且len(m1+c1+c4)=len(m2+c2+c4)=len(m3+p3+c5)。
一份公開的CPC攻擊源代碼是由Mark Stevens編寫的HashClash [2],支持使用CUDA來加速CPC攻擊中的生日攻擊部分,然而這份代碼目前不能很好工作。一份能工作的代碼在 [11]中可以找到。由于CUDA接口的升級,[2,11]中的CUDA部分均不能正常編譯。在做了一些修正后我們把現(xiàn)在可以工作的版本公布在 [12]中,供網(wǎng)友實驗。
使用 [12],我們構(gòu)造了兩組hash碰撞,大小分別為704字節(jié)和1048576字節(jié)(1Mb)。在我們雙路E5-2650V3的服務(wù)器上,我們使用了30個核心和3塊K1200加速卡,運算6小時可得到一組碰撞。其中使用加速卡進行生日攻擊的時間只有不到十分鐘。
A. 偽造CA證書
在MarcStevens 2009年的工作中,展示對CA證書的攻擊使用的是選擇前綴攻擊。圖1展示了偽造CA證書的原理 [10]。
圖1 CA證書的偽造過程
圖1左側(cè)是合法的網(wǎng)站證書結(jié)構(gòu),右側(cè)是需要偽造的CA證書結(jié)構(gòu)。進行攻擊時,攻擊者可以同時控制左側(cè)的合法網(wǎng)站證書結(jié)構(gòu),和右側(cè)的偽造CA證書的結(jié)構(gòu)。這里攻擊者需要對頭部幾個域(serial number/validity period)等進行"猜測",但是由于很強的可預(yù)測性,做這個猜測并不難。攻擊者通過對發(fā)行證書的機構(gòu)進行反復(fù)觀測(反復(fù)申請證書),發(fā)現(xiàn)1. 序列號是線性增加的并且2. 有效期是可預(yù)測的。因此攻擊者可以計劃一個攻擊的時間,并猜測那個時間段可能出現(xiàn)的序列號范圍,并構(gòu)造其對應(yīng)有效期,構(gòu)造出一批可能的合法證書頭部,作為選擇前綴攻擊的消息前綴。而對于右側(cè)偽造的CA證書,則構(gòu)造了一個合法的CA證書頭部。接下來攻擊者就進行大量運算,計算出一批碰撞。接下來再對做出的碰撞進行尾部補全,得到一批“合法網(wǎng)站證書”和“偽造CA證書”,并且從“合法網(wǎng)站證書”中取出RSA公鑰。最后,在攻擊者精心計劃的攻擊時間,去申請網(wǎng)站證書。如果申請下來的網(wǎng)站證書的序列號/有效期恰好匹配到攻擊者預(yù)測范圍內(nèi)的某一個證書,那么攻擊就完成了,生成了一個完全“有效”的偽造的CA證書。
2007年,Alexander Sotirov和Marc Stevens的團隊使用了200臺PS3主機進行了基于MD5 CPC攻擊的CA證書偽造攻擊。每一次計算耗時1-2天,在失敗了3次后,第四次終于成功。
B.SHA1 SHAttered攻擊
今年2月,SHA1的碰撞攻擊SHAttered首次公開在互聯(lián)網(wǎng)上。SHAttered攻擊屬于共同前綴攻擊,其展示形式非常直觀--兩個大小相等、SHA1值相同,但是顯式效果迥異的PDF文檔。
圖2 SHAttered攻擊的實例
該攻擊的難點有二,一是如何完成SHA1共同前綴攻擊,二是如何使用共同的前綴和后綴,以及不同的碰撞塊,構(gòu)造兩個合法的PDF,并且他們的顯示效果不同。
第一個問題,Marc Stevens已經(jīng)為此研究數(shù)年。這次他聯(lián)合了Google的工程師終于把算法變成現(xiàn)實。在這次攻擊中,他們使用了CPU來計算碰撞塊的第一個block,使用GPU來計算碰撞塊的第二個block。碰撞塊的第一個block的第一次碰撞消耗了3583核-年的計算量,第二次碰撞消耗了2987核-年的計算量。在第二階段,除了CPU外,還是用了GPU集群進行運算。GPU集群的計算量相當(dāng)于114塊K20計算一年,或是95塊K40計算一年,或是71塊K80一年的計算量。如果使用商業(yè)的云GPU服務(wù),租用71塊K80計算一年,就將耗費56萬美元。
對于第二個問題,該攻擊做了非常巧妙的構(gòu)造。我們借用熱心網(wǎng)友的回答 [17] 來做分析。首先,SHAttered攻擊是一個共同前綴攻擊,所以構(gòu)成的pdf一定是有一個共同的pdf頭部,參見圖3。
圖3 SHAttered攻擊的PDF結(jié)構(gòu)
兩個PDF的頭部共同部分包括:PDF文件頭和image對象的一部分。在image對象中,包括了屬性表引用、content結(jié)構(gòu),和屬性。該攻擊構(gòu)造了一個巧妙的content結(jié)構(gòu),在這個結(jié)構(gòu)中包含了一個JPEG圖片。碰撞塊Magic block 1和Magic block 2就位于這個JPEG圖片內(nèi)部metadata的部分,見圖4。
圖4 JPEG metadata部分的結(jié)構(gòu)
注意其中的FFFE comment處。FF FE 這兩個字節(jié)代表了comment段的開始,其后的兩個字節(jié)代表該comment段的長度。在圖4中出現(xiàn)了兩個comment段,第一個段的長度是0x24,用該comment段的起始地址0x99+0x24可以得到第二個comment段的地址0xBD。可以看到0xBD位置處依然是一個FF FE標(biāo)簽,代表另一個comment段的開始。這個comment段的長度在兩份pdf中就不相同了,在第一份pdf中,這個長度是0x173(指向0xBF+0x173=0x232),而在另一份pdf中,這個長度是0x17F(指向0xBF+0x17F=0x23E)。0x232開始的位置是一個很長的區(qū)段,而0x23E開始的部分是一個非常短的區(qū)段。其后還有一些精心布置的區(qū)段,它們的字節(jié)表示都一樣,但是由碰撞塊的第一字節(jié)引起差別后,所能表示的結(jié)構(gòu)不同,從而使得顯示出來的圖像不同。
C. 對網(wǎng)盤的“秒傳”機制進行攻擊
總所周知,網(wǎng)盤的“秒傳”機制可以大大減少文件上傳的時間代價?!懊雮鳌睓C制往往使用hash函數(shù)生成文件的摘要值來作為文件特征值,判斷是否可以使用“秒傳”功能。另一個影響“秒傳”機制的參量是文件大小。往往大文件會觸發(fā)“秒傳”機制,而小文件不一定觸發(fā)。
這里我們使用網(wǎng)易網(wǎng)盤、115網(wǎng)盤、城通網(wǎng)盤、騰訊網(wǎng)盤、中國移動彩云網(wǎng)盤、Box.com、Dropbox進行測試。除了網(wǎng)易網(wǎng)盤外,其他網(wǎng)盤均提供了對txt后綴文件的預(yù)覽功能。我們使用了一對704字節(jié)的碰撞和一對1MB字節(jié)的碰撞作為實驗文件,將他們上傳到網(wǎng)盤中,使用下載、預(yù)覽功能分別下載、預(yù)覽這兩個文件,測試各個網(wǎng)盤能否區(qū)分這兩個大小相等而且MD5值相同的文件。結(jié)果如下表。如果下載下來的兩個文件是相同的,則證明網(wǎng)盤無法區(qū)分這兩個文件,我們將這個測試結(jié)果標(biāo)記為“沖突”,否則標(biāo)記為“不沖突”。
可以看出,網(wǎng)易網(wǎng)盤、城通網(wǎng)盤和彩云網(wǎng)盤完全無法區(qū)分MD5碰撞的文件。
著名的virustotal網(wǎng)站曾經(jīng)使用MD5作為文件判重的標(biāo)準(zhǔn)以減少運算量。但是在CPC攻擊出現(xiàn)之后,攻擊者就可以通過先提交善意文件再傳播惡意文件的方式躲避來自virusltotal的報警。因此virustotal迅速進行了修改,使用SHA256的散列值作為文件特征。
目前很多安全廠商依然在使用md5用于惡意代碼識別,這里需要有額外的判重機制。由于MD5碰撞基本上都是屬于上文所述的同謀攻擊,因此如果相同MD5值下有一個樣本是惡意的,其他的樣本一般也是作為攻擊的中間環(huán)節(jié)而存在,將所有樣本都報警也是一種可行的辦法。
D. 攻擊基于“尾部附加key”形式的MD5簽名進行攻擊
我們先回顧上一篇文章 [13]中所述的在線支付協(xié)議中基于MD5的簽名機制。以請求“c=C&b=B&a=A”為例。為了簽名這個請求,先將請求解析為key-value對:
{"c":"C","b":"B","a":"A"}
然后按key的字典序進行排序并連接
a=A&b=B&c=C
附加上key
a=A&b=B&c=C&key=this_is_a_secret
計算MD5值
MD5(a=A&b=B&c=C&key=this_is_a_secret)=0a1d218f9b2b029c84c84458bb6dbc00
形成最終的請求
c=C&b=B&a=A&sign=0a1d218f9b2b029c84c84458bb6dbc00
這樣的請求存在于從支付平臺返回給商戶服務(wù)的支付結(jié)果異步通知中。商戶的驗簽過程通常是這樣的:
1、從參數(shù)中去掉sign域
2、將剩余參數(shù)decode,將每個接口的參數(shù)按照key值升序排列;
3、將排好序的參數(shù)按照 key=value&的形式鏈接為字符串;
4、將生成的字符串尾部附加上密鑰“key=token”,然后做MD5;
5、檢查MD5值是否等于sign域。若相等,則證明消息未被竄改。
這里我們注意到:驗簽時的參數(shù)列表默認是對“所有”參數(shù)驗簽。如果攻擊者可以在消息中插入一個域,那么就可以使得驗簽時也包括這個參數(shù)。由于此類系統(tǒng)的復(fù)雜性,這個請求往往很長,包括很多參數(shù)以及嵌套了許多層的商品信息。攻擊者一旦找到一個參數(shù)或者嵌套的參數(shù)可以注入,那么就可以控制異步通知的內(nèi)容。為了敘述方便,我們假定攻擊者下了兩個訂單,訂單Id分別為1704176438和1704176439。而且攻擊者可以控制參數(shù)“zzz”的尾部內(nèi)容,例如將請求設(shè)置為src的形式:
customerId=4&orderId=1704176438&service=querypay&version=1.0&zzz=
這里zzz=后面可以是任意給定內(nèi)容,這里留空也不影響。攻擊者構(gòu)造另一個請求dst:
customerId=4&orderId=1704176439&service=querypay&version=1.0&zzz=
這里只簡單修改了orderId以演示效果。然后通過CPC攻擊計算得出一組碰撞src.coll和dst.coll。由于攻擊者能控制zzz域,于是將src.coll進行真實支付,獲得支付平臺的簽名sign,然后將其異步通知中的訂單號做簡單修改,從1704176438改為1704176439,作為偽造的異步通知提交給商戶服務(wù)器。由于src.coll和dst.coll的MD5值是相等的,所以他們在尾部附加上商戶的密鑰之后做MD5值依然是相等的(MD5碰撞的尾部附加性質(zhì))。因此偽造的異步通知也是有效的。如果商戶服務(wù)器不去查賬而是相信支付平臺的異步通知,那么攻擊者成功的用一個訂單的金額完成了兩個訂單。
此外,之前也出現(xiàn)過針對微軟msi簽名機制不完善/雙簽名機制的攻擊,構(gòu)造具有“合法簽名”的惡意代碼。也發(fā)現(xiàn)了真實的利用CPC攻擊傳播的惡意代碼的實例。感興趣的讀者可以參考 [14]。
首先為了抵抗CPC攻擊,不能簡單的在待簽字符串后面附加密鑰,而是需要在待簽字符串前后均附加密鑰,即計算:
sign = hash(secret1 + string + secret2)
作為簽名。如果只在頭部附加,那么可能受到長度擴展攻擊影響。如果只在尾部附加,那么可能受到CPC攻擊的影響。但是如果兩端均附加,那么就不受到這兩類攻擊的影響了。此時,為了計算一個合法的碰撞,攻擊者不得不使用基于生日攻擊的蠻力搜索來進行攻擊。而且如果secret安全地存儲在云端,攻擊者必須要產(chǎn)生大量的網(wǎng)絡(luò)請求來完成碰撞,這個是難以實施且易于探測的。
如果存在同謀碰撞攻擊的可能,強烈建議前后同時都加簽名密鑰保護,而這也恰恰是HMAC [15,16] 的設(shè)計實現(xiàn)。因此在實際應(yīng)用中建議使用HMAC擴展算法,而不是直接使用MD5/SHA等算法,即使對于SHA256也是如此。
若不能直接升級到HMAC-SHA256算法,則要盡可能的消除同謀碰撞攻擊的機會,將攻擊退化成針對一個固定hash值的單向碰撞攻擊。在同謀碰撞攻擊(共同前綴攻擊和選擇前綴攻擊)中,由于碰撞塊的存在,需要對輸入有充分的自由選擇能力。若能嚴(yán)格的限制參與簽名的域,并且對參與簽名的每一個域進行嚴(yán)格檢查,則可以大幅度消除同謀攻擊的潛在機會。
真實世界中不乏易受同謀攻擊的例子。這里用AnySDK為例。AnySDK是一個第三方SDK接入工具,使用AnySDK可以接入許多不同在線支付平臺。AnySDK提供了一份典型的有風(fēng)險的驗簽代碼 [17],容易受到同謀攻擊威脅:
function checkSign($data, $privateKey) {
if (empty($data) || !isset($data['sign']) || empty($privateKey)) {
return false;
}
$sign =$data['sign'];
//sign 不參與簽名
unset($data['sign']);
$_sign =getSign($data,$privateKey);
if ($_sign!= $sign){
return false;
}
return true;
}
其中的getSign函數(shù)只是負責(zé)進行拼接待簽字符串和計算hash。可以看出,這份代碼對輸入的域并沒有任何限制,于是攻擊者的任何輸入均可進入驗簽過程中。這是相當(dāng)危險的,使用普通服務(wù)器運算幾小時即可生成完成MD5 CPC的運算,生成一組可用于發(fā)動攻擊的MD5碰撞,而成本只需幾元電費。若使用云計算平臺則可進一步提高速度。因此,這樣的簽名結(jié)構(gòu),搭配有缺陷的驗簽代碼,現(xiàn)在已經(jīng)非常危險。
以下是一份進行了良好的輸入?yún)?shù)驗證的示例代碼,可以最大程度的消除同謀碰撞的機會:
functioncheckSign($data, $privateKey) {
if (empty($data) || !isset($data['sign']) || empty($privateKey)) {
return false;
}
$this->params['arg1'] = $data['arg1'];
$this->params['arg2'] = $data['arg2'];
if (checkArgs($this->params) == false) {
return false;
}
$sign =$data['sign'];
$_sign =getSign($this->params,$privateKey);
if ($_sign!= $sign){
return false;
}
return true;
}
其中通過checkArgs函數(shù)對params數(shù)組的每個域進行合法性檢查,通過后再進行簽名計算。
在實施了這些防護措施之后,同謀碰撞攻擊將會近似退回到原根攻擊,目前估計針對MD5的攻擊復(fù)雜度將超過112bit,而針對SHA1的攻擊復(fù)雜度將超過144bit,在可見的近期代價依然非常高昂,不是普通機構(gòu)能夠承擔(dān)。
種種關(guān)于MD5/SHA1是否過時的討論已經(jīng)持續(xù)多年,但是由于國內(nèi)的實際情況,MD5/SHA1依然存在于我們?nèi)粘I畹拿總€方面,要替換的過程依然漫長。我們在對實際系統(tǒng)中的MD5/SHA1進行攻擊分析后發(fā)現(xiàn),在完善了驗簽、判重機制并盡可能消除同謀碰撞后,其安全性短期之內(nèi)還是可以得到保證的。盡管如此,這樣的機制只是給了我們難得的喘息時間,我們依然督促各廠商盡快升級到更安全的HMAC-SHA256。最后再次強調(diào),所有可能被長度擴展攻擊的數(shù)字簽名協(xié)議(節(jié)2.1)應(yīng)該立即升級成第四節(jié)中所述的HMAC-SHA256算法,因為很有可能黑產(chǎn)已經(jīng)在享用你的服務(wù)了。
參考文獻
1. Cryptographic Hash Function,https://en.wikipedia.org/wiki/Cryptographic_hash_function
2. The HashClash Project, http://www.win.tue.nl/hashclash/
3. Create your own MD5 collisions,https://natmchugh.blogspot.com/2015/02/create-your-own-md5-collisions.html
4. MD5長度擴展攻擊,https://zh.wikipedia.org/wiki/長度擴展攻擊
5. 哈希長度擴展攻擊解析,ricterzheng,https://ricterz.me/posts/哈希長度擴展攻擊解析
6. MD5長度擴展攻擊原理,http://blog.nsfocus.net/tech/技術(shù)分享/2016/06/27/MD5長度擴展攻擊原理.html
7. How to break MD5 and other hash functions,http://dl.acm.org/citation.cfm?id=2154601
8. How To Find Weak Input Differences For MD5 Collision Attacks,http://eprint.iacr.org/2009/223.pdf
9. MD5 Chosen Prefix Collision,https://www.win.tue.nl/hashclash/ChosenPrefixCollisions/
10. Creating a rogue CA certificate,http://www.win.tue.nl/hashclash/rogue-ca/
11. Create your own MD5 collisions,https://natmchugh.blogspot.com/2015/02/create-your-own-md5-collisions.html
12. MD5碰撞示例代碼,https://github.com/dingelish/md5-cpc
13. 支付安全不能說的那些事,百度安全實驗室公眾號
14. MD5碰撞的演化之路,http://bobao.#/learning/detail/2577.html
15. Keying hash functions for message authentication, Mihir Bellare ,Ran Canetti , Hugo Krawczyk
16. How did the Shattered.iogroup manage to create a SHA1 collision for a PDF that is similar looking tothe original?,https://security.stackexchange.com/questions/152341/how-did-the-shattered-io-group-manage-to-create-a-sha1-collision-for-a-pdf-that
17. AnySDK簽名算法及示例, http://docs.anysdk.com/integration/server/payment-notice/
雷峰網(wǎng)特約稿件,未經(jīng)授權(quán)禁止轉(zhuǎn)載。詳情見轉(zhuǎn)載須知。