HTTPS連接最初的若干毫秒
作者 Jeff Moser 譯者 馬國(guó)耀 發(fā)布于 2009年9月23日 上午12時(shí)28分
當(dāng)你在瀏覽了一個(gè)網(wǎng)站上面的商品之后,點(diǎn)擊“繼續(xù)并結(jié)帳”時(shí)會(huì)發(fā)生什么?本文即將對(duì)(瀏覽器)與Amazon建立安全連接的整個(gè)過(guò)程中最初的若干毫秒進(jìn)行分析。當(dāng)你點(diǎn)擊繼續(xù)按鈕時(shí)一個(gè)新的頁(yè)面將被加載:
在短暫的220毫秒內(nèi),發(fā)生了很多有趣的事情,F(xiàn)irefox修改了地址欄的顏色,并在其右下角放置了一個(gè)鎖狀的圖標(biāo)。在我最喜愛(ài)的網(wǎng)絡(luò)工具Wireshark以及略微修改的Firefox調(diào)試版的幫助下,我們可以對(duì)正在發(fā)生的事情看個(gè)究竟。
根據(jù)RFC 2818協(xié)議的規(guī)定,F(xiàn)irefox明白“https”意味著它應(yīng)該連接Amazon.com的443端口:
大多數(shù)人將HTTPS和SSL(Secure Sockets Layer)聯(lián)系起來(lái),SSL是Netscape公司在90年代中期發(fā)明的。隨著時(shí)間的推移這種說(shuō)法就漸漸變得不準(zhǔn)確了。由于Netscape失去了市場(chǎng)份額,它將SSL的維護(hù)工作移交給因特網(wǎng)工程任務(wù)組(IETF)。第一個(gè)后Netscape版本被重新命名為安全傳輸層協(xié)議(TLS),TLS1.0是在1999年1月份發(fā)布的。由于TLS誕生都10年了, 所以真正的“SSL”傳輸其實(shí)是幾乎見(jiàn)不到。
Client Hello
TLS將所有的網(wǎng)絡(luò)傳輸打包成不同的“記錄”類型。我們看到從瀏覽器出來(lái)的第一個(gè)字節(jié)是一個(gè)十六進(jìn)制(hex)字節(jié)0x16=22,這說(shuō)明它是一個(gè)“握手”記錄:
后面的兩個(gè)字節(jié)是0x0301,意味著它的版本是3.1,事實(shí)上TLS1.0就是SSL3.1。
“握手”記錄被分解成若干消息。第一個(gè)就是“Client Hello”消息(0x01)。這里面有很重要的幾點(diǎn):
隨機(jī)數(shù):
前面的四個(gè)字節(jié)是當(dāng)前的協(xié)調(diào)世界時(shí)(Coordinated Universal Time,UTC),它的格式是Unix時(shí)間戳,也就是從1970年1月1日起到此刻所經(jīng)歷的秒數(shù)。在本例中的該數(shù)字是0x4a2f07ca。跟隨其后是28字節(jié)的隨機(jī)數(shù),它將在后面使用。 會(huì)話標(biāo)識(shí)(session id):
在這里它是空值或者是null。如果在幾秒前該瀏覽器曾連接過(guò)Amazon.com,它就可能繼續(xù)使用前面的會(huì)話,而不需要重新執(zhí)行整個(gè)“握手”過(guò)程。 密碼套件:
它是瀏覽器所支持的密碼算法的一個(gè)列表。最上面的是一個(gè)很強(qiáng)大的組合“TLS_ECDHE_ECDSA_與_AES_256_CBC_SHA,下面還有該瀏覽器支持的另外33個(gè)選擇。如果現(xiàn)在不明白它們的含義也不必?fù)?dān)心,后面你將會(huì)發(fā)現(xiàn)Amazon并沒(méi)有選擇最上面的強(qiáng)大組合。 server_name extension:
通過(guò)它告訴Amazon.com,瀏覽器正要連接https://www.amazon.com/。這樣做非常方便,因?yàn)門LS“握手”發(fā)生在所有的HTTP傳輸之前 。HTTP協(xié)議中有一個(gè)“Host”頭, 這就允許了Internet托管公司出于成本的考慮將上百個(gè)網(wǎng)站綁定在同一IP 地址上。傳統(tǒng)意義上SSL要求每一個(gè)地址有一個(gè)不同的IP,而這個(gè)擴(kuò)展就使得服務(wù)器能夠正確響應(yīng)瀏覽器所請(qǐng)求的(服務(wù)器)證書(shū)。最后注意一點(diǎn),對(duì)于 IPv4的地址這一擴(kuò)展的有效期大概能再多一周左右。 Server Hello
對(duì)應(yīng)于Client Hello,Amazon.com也返回一個(gè)“握手”記錄,它是兩個(gè)龐大的數(shù)據(jù)包(2,551字節(jié))。該記錄的版本號(hào)是0x0301,也就意味這Amazon支持我們使用的TLS1.0版本的請(qǐng)求。這個(gè)記錄分成三個(gè)子消息,他們包含著一些有趣的信息。
"Server Hello" 消息(2):
? 我們得到服務(wù)器返回的四字節(jié)的Unix時(shí)間戳以及28字節(jié)的隨機(jī)數(shù),它也將在后面使用(譯注:注Clien Hello是發(fā)了一個(gè)隨機(jī)數(shù),這兩個(gè)隨機(jī)數(shù)將用于產(chǎn)生最后的對(duì)稱密鑰)。 一個(gè)32字節(jié)的會(huì)話標(biāo)識(shí),有了它,隨后重連服務(wù)器就不需要再執(zhí)行一個(gè)完整的握手過(guò)程了。 從我們提供的34個(gè)可選的密碼套件中,Amazon選擇的套件“TLS_RSA_WITH_RC4_128_MD5”(0x0004)。也就是說(shuō)它將使用“RSA” 公鑰算法來(lái)驗(yàn)證證書(shū)以及交換密鑰,用RC4加密算法對(duì)數(shù)據(jù)進(jìn)行加密,使用MD5哈 希算法來(lái)校驗(yàn)消息內(nèi)容。后面會(huì)對(duì)它們做詳細(xì)介紹。我個(gè)人認(rèn)為Amazon選擇這個(gè)密碼套件的原因是出于自私的考慮(譯注:這里說(shuō)“自私”的意思 是,Amazon出于性能的考慮,降低了安全的強(qiáng)度)。這個(gè)套件是這34個(gè)套件中消耗CPU最少的一個(gè),因此Amazon選擇它就是為了節(jié)省一些CPU來(lái) 處理更多的用戶連接。還有一個(gè)不大可能的原因是他們要特別地向Ron Rivest致敬,這個(gè)套件中所用到的三個(gè)算法都是他發(fā)明的。 證書(shū)消息(11):
這個(gè)巨大的消息占據(jù)了2464個(gè)字節(jié),它是一個(gè)證書(shū),客戶端用它對(duì)Amazon進(jìn)行認(rèn)證。它并不是什么花哨的玩意,通過(guò)瀏覽器就可以看到它的大部分內(nèi)容:
“Server Hello 結(jié)束”消息(14):
這是一個(gè)0字節(jié)的消息,它告訴客戶端“hello”過(guò)程已經(jīng)完成,也就意味著服務(wù)端將不驗(yàn)證客戶端的證書(shū)。
校驗(yàn)證書(shū)
瀏覽器必須要確定它是否要信任Amazon.com,在這里是通過(guò)證書(shū)判斷的。它檢查Amazon的證書(shū)并且檢查現(xiàn)在的時(shí)間是否在證書(shū)的有效期之內(nèi),該有效期規(guī)定的是“不能早于”2008年8月26日且“不能晚于”2009年8月27日。此外,它還要確保該證書(shū)的公鑰已經(jīng)被授權(quán)在進(jìn)行密鑰交換的過(guò)程中使用。
為什么我們應(yīng)該相信這個(gè)證書(shū)呢?
在證書(shū)上附有一份“簽名”,這個(gè)簽名事實(shí)上是一個(gè)big-endian(譯注:Big-Endian和Little-Endian是一種二進(jìn)位資料儲(chǔ)存或傳輸?shù)母袷剑珺ig-Endian的最高位字節(jié)在最前頭,而Little-Endian的最高位字節(jié)在最后面)格式的長(zhǎng)整型數(shù):
任何人都有可能發(fā)給我們這些字節(jié),為什么我們要相信這個(gè)簽名呢?為了回答這個(gè)問(wèn)題,有必要先到這里mathemagic land去速成一些相關(guān)知識(shí):
穿插:簡(jiǎn)短的,不那么可怕的RSA向?qū)?/p>
有時(shí)候人們想知道數(shù)學(xué)和編程有何聯(lián)系。證書(shū)就是應(yīng)用數(shù)學(xué)的一個(gè)非常實(shí)際的例子。Amazon的證書(shū)告訴我們應(yīng)該用RSA算法來(lái)校驗(yàn)其簽名。RSA是MIT的教授Ron Rivest,Adi Shamir和Len Adleman在70年代創(chuàng)造出來(lái)的,他們?nèi)藙?chuàng)造了一個(gè)巧妙的方法將2000多年來(lái) 數(shù)學(xué)發(fā)展的思想?yún)R合起來(lái)形成了一個(gè)漂亮而簡(jiǎn)單的算法:
首先選擇兩個(gè)很大的質(zhì)數(shù)“p”和“q”,并對(duì)他們求積得到“n=p*q”。接下來(lái),取一個(gè)較小的“e”作為指數(shù),它用作“加密指數(shù)”,而對(duì)e的進(jìn)行特殊的逆反函數(shù)計(jì)算所得到的“d”作為“解密指數(shù)”。然后將“n”和“e”公開(kāi)出去,而對(duì)“d”要保密,對(duì)于“p”和“q”你可以把它們?nèi)拥?,也可以像“d”一樣保密起來(lái)。真正重要的要記住“d”和“e”是相互的逆反。
現(xiàn)在,如果你有一些消息,那么你只需要將該消息的字節(jié)翻譯成一個(gè)數(shù)“M”,若要對(duì)這個(gè)消息進(jìn)行“加密”形成“密文”的話,你就這么計(jì)算:
C ≡ Me (mod n)
它意思是先求“M”的“e”次方,然后對(duì)它應(yīng)用模數(shù)“n”求余。舉個(gè)例子,11AM +3 hours ≡ 2 (PM)(mod 12 hours)。接收者知道(解密用的)“d”,而“d”可以對(duì)已加密的消息進(jìn)行反轉(zhuǎn)并還原消息:
Cd ≡ (Me)d ≡ Me*d ≡ M1 ≡ M (mod n)
另一件有意思的事情是拿著“d”的人可以對(duì)一個(gè)文檔進(jìn)行簽名,其做法是文檔“M”求“d”次冪然后應(yīng)用模數(shù)“n”求余數(shù)“S”:
Md ≡ S (mod n)
這種做法成立的原因是“簽名者”將“S”,“M”,“e”以及“n”公開(kāi)出去,任何人都可以通過(guò)這樣一個(gè)簡(jiǎn)單的計(jì)算來(lái)驗(yàn)證“S”是否由“簽名者”所簽(譯 注:因?yàn)槊總€(gè)“e”都是某個(gè)簽名者所獨(dú)有的,而“e”和“d”是成對(duì)出現(xiàn)的,所以簽名者用自己的“d”簽名,只能拿這個(gè)“d”所對(duì)應(yīng)的“e”才能還原消息,這就到了簽名的作用):
Se ≡ (Md)e ≡ Md*e ≡ Me*d ≡ M1 ≡ M (mod n)
像RSA這樣的公鑰密碼算法經(jīng)常被稱之為“非對(duì)稱”算法,因?yàn)榧用艿拿荑€(本例子中的“e”)和解密的密鑰是不相同的(本例子中是“d”)。對(duì)所有的數(shù)應(yīng)用“mod n”的目的是使攻擊者不可能使用簡(jiǎn)單的技術(shù)(如過(guò)去我們使用的對(duì)數(shù))破解它。RSA的神奇之處是你可以很快計(jì)算/加密C ≡ Me (mod n),而在不知道“d”的情況下計(jì)算/解密Cd ≡ M (mod n)是非常困難的。如前面所說(shuō),“d”來(lái)自于對(duì)“n”的因子分解,而“n”來(lái)自于“p”和“q”,求解“d”是一件復(fù)雜的事情。
簽名驗(yàn)證
在現(xiàn)實(shí)世界里使用RSA時(shí)應(yīng)該謹(jǐn)記的重要的一點(diǎn)是,前文提到的所有數(shù)字都應(yīng)是很大的數(shù),只有這樣才能保證,即使用目前最好的算法也 很難攻破上述算法。到底多大才算很大的數(shù)呢?Amazon.com的證書(shū)是由“VeriSign Class 3 Secure Server CA.” 簽名的。從這個(gè)證書(shū)中我們可以看出,VeriSign所使用的模數(shù)“n”是一個(gè)2048比特長(zhǎng)的數(shù)字,表示成10進(jìn)制數(shù)的長(zhǎng)度是617位:
1890572922 9464742433 9498401781 6528521078 8629616064 3051642608 4317020197 7241822595 6075980039 8371048211 4887504542 4200635317 0422636532 2091550579 0341204005 1169453804 7325464426 0479594122 4167270607 6731441028 3698615569 9947933786 3789783838 5829991518 1037601365 0218058341 7944190228 0926880299 3425241541 4300090021 1055372661 2125414429 9349272172 5333752665 6605550620 5558450610 3253786958 8361121949 2417723618 5199653627 5260212221 0847786057 9342235500 9443918198 9038906234 1550747726 8041766919 1500918876 1961879460 3091993360 6376719337 6644159792 1249204891 7079005527 7689341573 9395596650 5484628101 0469658502 1566385762 0175231997 6268718746 7514321
(如果你要試圖從這個(gè)“n”中找到“p”和“q”那就祝你好運(yùn),假如你能找到他們,那么你能產(chǎn)生像真的一樣的VeriSign證書(shū)了)
VeriSign的“e”的值是2^16 + 1 = 65537。當(dāng)然,他們對(duì)相應(yīng)的“d”保密,也許被放在一個(gè)安全的硬件設(shè)備上,由視網(wǎng)膜掃描機(jī)和武裝部隊(duì)保護(hù)著。在簽名之前,VeriSign要通過(guò)現(xiàn)實(shí)世界的“握手”來(lái)驗(yàn)證Amazon.com聲明的證書(shū)內(nèi)容,包括審查他們的很多商務(wù)文檔。一旦VeriSign對(duì)這些文檔滿意了,他們使用SHA-1哈希算法對(duì)包含所有聲明的證書(shū)進(jìn)行計(jì)算獲得一個(gè)哈希值。在Wireshark中看到整個(gè)證書(shū)的樣子如下圖“signedCertificate”部分所示:
上面的說(shuō)法(整個(gè)證書(shū)如同signedCertificate所示)說(shuō)有點(diǎn)用詞不當(dāng),因?yàn)樽C書(shū)的實(shí)際含義是簽名者將要進(jìn)行簽名的部分,而不是已經(jīng)包含了簽名信息的字節(jié)。
實(shí)際的簽名,也就是“S”,是Wireshark包中簡(jiǎn)單地稱為“encrypted”的部分(見(jiàn)上圖)。如果我們求“S”的“e”次冪(“e”是VeriSign公開(kāi)的),然后在對(duì)該結(jié)果取模“n”并得到余數(shù),那么我們得到的“已解密”十六進(jìn)制簽名是:
0001FFFFFFFFFFFF FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF FFFFFFFF00302130 0906052B0E03021A 05000414C19F8786 871775C60EFE0542 E4C2167C830539DB
基于PKCS #1 v1.5標(biāo)準(zhǔn), 最開(kāi)始的字節(jié)是“00”,它“保證了加密塊被轉(zhuǎn)換成整數(shù)之后,大小不會(huì)超過(guò)模數(shù)”。第二個(gè)字節(jié)“01”說(shuō)明這是一個(gè)私鑰操作(如,它是一個(gè)簽名)。后面是 一大堆“FF”,用他們填充這個(gè)結(jié)果,使之足夠大。填充字節(jié)以“00”結(jié)束,后面跟的是"30 21 30 09 06 05 2B 0E 03 02 1A 05 00 04 14",PKCS #1 v2.就是這樣來(lái)指定SHA-1哈希算法。最后的20個(gè)字節(jié)是對(duì)“signedCertificate”部分的SHA-1哈希摘要。
因?yàn)榻饷艿闹涤兄_的格式并且最后的字節(jié)和我們獨(dú)立計(jì)算得到的哈希值相同,我們可以認(rèn)為這就是由擁有“VeriSign Class 3 Secure Server CA”私鑰的人所簽名的,而我們隱含地信任只有VeriSign知道這個(gè)私鑰“d”。
但我們?yōu)槭裁匆湃嗡??因?yàn)樵谛湃捂溕弦呀?jīng)沒(méi)有更高級(jí)別了。
最上層的“VeriSign Class 3 Public Primary Certification Authority”是自簽名的。這個(gè)證書(shū)自從網(wǎng)絡(luò)安全服務(wù)(Network Security ServicesNSS)庫(kù)中certdata.txt的1.4版本之后就已經(jīng)被嵌入Mozilla的產(chǎn)品中作為一個(gè)隱含的受信證書(shū)。它是由NetScape的Robert Relyea在2000年9月6日登記進(jìn)去的,當(dāng)時(shí)他還留下以下評(píng)注:
"用這個(gè)框架來(lái)收集其他網(wǎng)絡(luò)安全服務(wù),它包括這一個(gè)“實(shí)時(shí)的”certdata.txt ,里面存放了那些我們已經(jīng)獲得許可權(quán)可以推向開(kāi)源的證書(shū)(當(dāng)我們從所有者那里獲得許可權(quán)之后,會(huì)有更多的證書(shū)加入這個(gè)文檔中)”
由于該證書(shū)的有效期范圍是從1996年1月28日到2028年8月1日,所以這個(gè)決定是意義深遠(yuǎn)的。
Ken Thompson在他的“Reflection on Trusting Trust”中解釋的非常好,你最終不得不隱式地信任某人。在這個(gè)問(wèn)題上別無(wú)選擇。本例中我們隱含地信任Robert Relyea做了個(gè)好的選擇,我們也希望Mozilla的內(nèi)建證書(shū)策略對(duì)其他的內(nèi)建證書(shū)也是合理的。
這里要記住的一點(diǎn)是所有這些證書(shū)和簽名都簡(jiǎn)單地用來(lái)形成一個(gè)信任鏈。在公共網(wǎng)絡(luò)中,在你還未上任何網(wǎng)站之前,F(xiàn)irefox就已經(jīng)隱含地信任了VeriSign的根證書(shū)。在一個(gè)公司內(nèi),你可以創(chuàng)建你自己的根證書(shū)CA,并將它安裝在每個(gè)人的電腦上。
或者,你還可以付錢給VeriSign這樣的公司并把所有的證書(shū)信任鏈的工作交給它。證書(shū)用來(lái)通過(guò)可信的第三方(這里是VeriSign)建立信任 關(guān)系。如果你可以安全地和別人共享密鑰,比如“在某人耳邊輕聲告訴他一長(zhǎng)串密碼”,那么你就可以使用預(yù)共享密鑰(PSK,Pre-shared Kay)認(rèn)證來(lái)建立信任關(guān)系。TLS對(duì)此也有擴(kuò)展,比如TLS-PSK,以及我本人所喜歡的TLS的安全遠(yuǎn)程密碼擴(kuò)展。然而,這些擴(kuò)展沒(méi)能被廣泛地使用和支持,所以他們通常是不切實(shí)際的。此外,這些方法增加了負(fù)擔(dān),它們要求必須通過(guò)安全的方式交換密鑰,而這比通過(guò)TLS來(lái)建立信任連接的負(fù)擔(dān)更重(要不然我們何不都這么用呢?)。
我們要做的最后的檢查是驗(yàn)證證書(shū)上的主機(jī)名是否是我們期待訪問(wèn)的。 Nelson Bolyard 在 SSL_AuthCertificate 函數(shù)中的注釋是這樣解釋的:
/*?證書(shū)是沒(méi)問(wèn)題的。這是SSL連接的客戶端。
*現(xiàn)在要檢查證書(shū)中的名字和所期待的主機(jī)名是否一致。
*注意:這是我們防范中間人(Man-In-The-Middle)攻擊的唯一途經(jīng)*/
這個(gè)檢查防范了中間人攻擊,因?yàn)槲覀冸[含地相信擁有證書(shū)的人不會(huì)干壞事,例如,只有它真是Amazon.com,它才會(huì)對(duì)一個(gè)證書(shū)簽名說(shuō)它是Amazon.com。如果一個(gè)攻擊者能夠通過(guò)類似 DNS緩存破壞的技術(shù)修改我們的DNS服務(wù)器,你可能被蒙蔽了,以為自己正訪問(wèn)正確的網(wǎng)站(如Amazon.com),因?yàn)槟愕臑g覽器的地址欄看起來(lái)就是這個(gè)網(wǎng)站。這最后的檢查就隱含地信任證書(shū)的授權(quán)機(jī)構(gòu)可以防止壞事的發(fā)生。
Pre-Master Secret
現(xiàn)在我們已經(jīng)驗(yàn)證了Amazon.com的那些聲明,并且知道其公開(kāi)的加密指數(shù)“e”和模數(shù)“n”。任何在網(wǎng)絡(luò)上偵聽(tīng)的人當(dāng)然也知道這兩個(gè)數(shù)(這點(diǎn) 很明顯,因?yàn)槲覀兪峭ㄟ^(guò)Wireshark獲取它們的,別人也可以)?,F(xiàn)在我們要?jiǎng)?chuàng)建一個(gè)攻擊者或偷聽(tīng)者不能辨別的隨機(jī)密鑰,這件事做起來(lái)不像聽(tīng)起來(lái)那么簡(jiǎn)單。在1996年,研究者發(fā)現(xiàn)Netscape Navigator1.1僅使用三個(gè)數(shù)據(jù)源來(lái)作為他們的偽隨機(jī)數(shù)生產(chǎn)器的種子(PRNG),它們是:當(dāng)前時(shí)間,進(jìn)程號(hào)和父進(jìn)程號(hào)。研究顯示,這些“隨機(jī)”源并不那么隨機(jī),而且相對(duì)比較容易被猜出來(lái)。
由于其他的所有東西都是從這三個(gè)“隨機(jī)”源產(chǎn)的,在1996年當(dāng)時(shí)的機(jī)器上可能只需25秒中就可以“攻破”SSL“安全”。如果你還不相信尋找隨機(jī)數(shù)是件困難的事,只要問(wèn)問(wèn)Debian OpenSSL維護(hù)者就知道了。如果隨機(jī)數(shù)搞亂了,那么基于它之上的所有安全都是可疑的。
在Windows上,用于加解密的隨機(jī)數(shù)是通過(guò)調(diào)用CryptGenRandom函數(shù)對(duì)來(lái)自125個(gè)源的抽樣數(shù)據(jù)求hash值產(chǎn)生的。Firefox將該函數(shù)產(chǎn)生的隨機(jī)數(shù)和它自己的函數(shù)產(chǎn)生的比特碼一起作為偽隨機(jī)數(shù)生成器的種子。
雖然這個(gè)48字節(jié)的“pre-master secret”隨機(jī)數(shù)并不直接使用,但是保證其私密性是非常重要的,因?yàn)楹芏鄸|西都是由它而來(lái)的。毫無(wú)疑問(wèn),F(xiàn)irefox讓我們很難看到這個(gè)數(shù)。我不得不編譯了一個(gè)調(diào)試版本并設(shè)置SSLDEBUGFILE和SSLTRACE兩個(gè)環(huán)境變量才能看到它。
在本次會(huì)話中,SSLDEBUGFILE中顯示的這個(gè)pre-master secret是這樣的:
4456: SSL[131491792]: Pre-Master Secret [Len: 48]
03 01 bb 7b 08 98 a7 49 de e8 e9 b8 91 52 ec 81 ...{...I.....R..
4c c2 39 7b f6 ba 1c 0a b1 95 50 29 be 02 ad e6 L.9{......P)....
ad 6e 11 3f 20 c4 66 f0 64 22 57 7e e1 06 7a 3b .n.? .f.d"W~..z;
需要指出的是這并非全是隨機(jī)數(shù), 按約定,最前面的兩個(gè)字節(jié)是TLS版本(03 01)。
密鑰交換
現(xiàn)在要把這個(gè)密鑰傳給Amazon.com。由于Amazon選擇的是“TLS_RSA_WITH_RC4_128_MD5”,我們將使用RSA算 法來(lái)做這件事。輸入消息可以是正好48字節(jié)的pre-master secret,但是公鑰密碼學(xué)標(biāo)準(zhǔn)(PKCS)#1,RFC1.5 要求用一些隨機(jī)數(shù)來(lái)填充這個(gè)數(shù)使其長(zhǎng)度等于模數(shù)的長(zhǎng)度(1024比特,或者128字節(jié))。這樣做就使得攻擊者更難找出我們的pre-master secret了,另外,萬(wàn)一有人做傻事,比如重用相同的密鑰,它還為我們提供最后一層保護(hù)。通過(guò)這樣一填充,即使我們重用密鑰,偷聽(tīng)者在網(wǎng)絡(luò)上兩次看到的數(shù)也是不一樣的。
又,因?yàn)镕irefox讓我們很難看到這些隨機(jī)數(shù),我不得不在填充函數(shù)中加入一些調(diào)試語(yǔ)句才能看到發(fā)生的事情:
在這次會(huì)話中,填充后的消息如下所示:
00 02 12 A3 EA B1 65 D6 81 6C 13 14 13 62 10 53 23 B3 96 85 FF 24 FA CC 46 11 21 24 A4 81 EA 30 63 95 D4 DC BF 9C CC D0 2E DD 5A A6 41 6A 4E 82 65 7D 70 7D 50 09 17 CD 10 55 97 B9 C1 A1 84 F2 A9 AB EA 7D F4 CC 54 E4 64 6E 3A E5 91 A0 06 00 03 01 BB 7B 08 98 A7 49 DE E8 E9 B8 91 52 EC 81 4C C2 39 7B F6 BA 1C 0A B1 95 50 29 BE 02 AD E6 AD 6E 11 3F 20 C4 66 F0 64 22 57 7E E1 06 7A 3B
Firefox拿這個(gè)數(shù)進(jìn)行計(jì)算“C ≡ Me (mod n)”,得到的數(shù)是我們?cè)诳蛻裘荑€交換記錄中所看到的
最后Firefox發(fā)出最后一條沒(méi)加密的消息,一個(gè)“Change Cipher Spec”記錄:
Firefox使用這種方式通知Amazon,它將使用前面協(xié)商好的密鑰來(lái)加密下一條消息。
生成Master Secret
如果前面所有事情都正確完成,則雙方(且只有這雙方,客戶端和服務(wù)端)現(xiàn)已知道這個(gè)48字節(jié)的pre-master secret。從Amazon的角度來(lái)看這里有一個(gè)很小的信任問(wèn)題:pre- master secret只包含客戶端生成的比特位,他們沒(méi)有考慮到服務(wù)端或者我們前面所提到的那些隨機(jī)數(shù)(譯注:Client hello和Server hello過(guò)程中產(chǎn)生的隨機(jī)數(shù))。我們將通過(guò)計(jì)算“master secret”來(lái)解決這個(gè)問(wèn)題。根據(jù)規(guī)約,應(yīng)該這么計(jì)算:
master_secret = PRF(pre_master_secret, "master secret", ClientHello.random + ServerHello.random)
“pre_master_secret”是客戶端之前發(fā)送的;“master secret”用的是一個(gè)字符串的ASCII值(例如:“6d 61 73 74 65 72 ...”)。然后我們將本文最開(kāi)始看到的ClientHello和ServerHello發(fā)送的隨機(jī)數(shù)拼接起來(lái)。
PRF是一個(gè)“偽隨機(jī)數(shù)函數(shù)”,這個(gè)函數(shù)很聰明,在規(guī)約中也有定義。它使用基于哈希的消息驗(yàn)證碼(HMAC)的MD5和SHA-1兩種哈希函數(shù)將密鑰,ASCII字符以及我們給的種子結(jié)合起來(lái)。對(duì)每個(gè)哈希函數(shù)發(fā)送一半的輸入。說(shuō)它聰明的原因是即使面對(duì)MD5和SHA-1的弱點(diǎn),它的防攻擊能力還很強(qiáng)。這個(gè)過(guò)程可以自我反饋并不停地循環(huán),而且我們要多少字節(jié)就能生成多少。
依照這個(gè)過(guò)程,我們獲得以下48字節(jié)的“master secret”:
4C AF 20 30 8F 4C AA C5 66 4A 02 90 F2 AC 10 00 39 DB 1D E0 1F CB E0 E0 9D D7 E6 BE 62 A4 6C 18 06 AD 79 21 DB 82 1D 53 84 DB 35 A7 1F C1 01 19
多個(gè)密鑰的生成
現(xiàn)在雙方都有了“master secrets”,規(guī)約描述了我們?nèi)绾紊蓵?huì)話所需的所有的密鑰,我們需要使用PRF函數(shù)來(lái)創(chuàng)建一個(gè)“key block”,然后從這個(gè)塊中提取所需的密鑰:
key_block = PRF(SecurityParameters.master_secret, "key expansion", SecurityParameters.server_random + SecurityParameters.client_random);
“key_block”被用來(lái)提取以下密鑰:
client_write_MAC_secret[SecurityParameters.hash_size]
server_write_MAC_secret[SecurityParameters.hash_size]
client_write_key[SecurityParameters.key_material_length]
server_write_key[SecurityParameters.key_material_length]
client_write_IV[SecurityParameters.IV_size]
server_write_IV[SecurityParameters.IV_size]
由于這里使用的是序列密碼而非分組密碼(如高級(jí)加密標(biāo)準(zhǔn)AES),所以不需要初始向量(Initialization Vectors IV),而只是雙方各需要一個(gè)16字節(jié)(128比特)的消息驗(yàn)證碼(Message Authentication Code MAC),這是因?yàn)橹付ǖ腗D5哈希摘要大小是16字節(jié)。另外,RC4加密算法使用的16字節(jié)的密碼也是雙方都需要的。最后,我們需要key block中的2*16 + 2*16 = 64個(gè)字節(jié):
運(yùn)行PRF,我們得到:
client_write_MAC_secret = 80 B8 F6 09 51 74 EA DB 29 28 EF 6F 9A B8 81 B0
server_write_MAC_secret = 67 7C 96 7B 70 C5 BC 62 9D 1D 1F 4A A6 79 81 61
client_write_key = 32 13 2C DD 1B 39 36 40 84 4A DE E5 6C 52 46 72
server_write_key = 58 36 C4 0D 8C 7C 74 DA 6D B7 34 0A 91 B6 8F A7
準(zhǔn)備加密!
客戶端發(fā)出的最后一條“握手”消息是“Finished message”。 這個(gè)消息非常巧妙,它不僅能證明沒(méi)有人篡改了握手過(guò)程,還能證明我們確實(shí)知道密鑰??蛻舳藢⑺械摹拔帐帧毕⒎湃胍粋€(gè) “handshake_messages”緩存區(qū),然后使用偽隨機(jī)函數(shù),“client finished”字符串以及MD5和SHA-1哈希運(yùn)算后“handshake_messages”計(jì)算出12字節(jié)的“verify_data”:
verify_data = PRF(master_secret, "client finished", MD5(handshake_messages) + SHA-1(handshake_messages)) [12]
我們?cè)谶@個(gè)結(jié)果的前面加上一個(gè)記錄頭字節(jié)“0x14”指明“完成”和長(zhǎng)度字節(jié)“00 00 0c”指明我們將發(fā)送12字節(jié)的“verify data”。然后,像所有接下來(lái)的加密消息一樣, 我們要確保解密后的內(nèi)容沒(méi)有被篡改。因?yàn)檫x擇使用的密碼套件是TLS_RSA_WITH_RC4_128_MD5,所以我們將使用MD5哈希函數(shù)。
有些人一聽(tīng)到MD5就感到恐慌,因?yàn)樗嬖谝恍┤觞c(diǎn),我原先也很不提倡使用它。然而,TLS很聰明,他并不直接使用MD5,而使用它的HMAC版本。TLS是這樣使用MDB進(jìn)行計(jì)算的:
HMAC_MD5(Key, m) = MD5((Key ⊕ opad) ++ MD5((Key ⊕ ipad) ++ m)
(⊕指的是異或(XOR),++指的是拼接,“opad”是一串“5c 5c ... 5c”字節(jié),“ipad”是另一串“36 36 ... 36”)。
這里我們對(duì)以下內(nèi)容進(jìn)行計(jì)算:
HMAC_MD5(client_write_MAC_secret, seq_num + TLSCompressed.type + TLSCompressed.version + TLSCompressed.length + TLSCompressed.fragment));
也許你已經(jīng)看到,我們加入了一個(gè)序列號(hào)(“seq_num”)和明文消息(這里被稱為TLSCompressed)的一些其他屬性。序列號(hào)可以迷惑 攻擊者,他可能會(huì)在中途把一個(gè)先前加密的消息插入。如果他這么干,則序列號(hào)一定和我們所期待的不一樣,這就保護(hù)了我們不受攻擊者們?nèi)酉⒌墓簟?/p>
剩下就是加密消息了。
RC4加密算法
從前文已知雙方協(xié)商的密碼套件是TLS_RSA_WITH_RC4_128_MD5。這就意味著我們將使用Ron's Code #4 (RC4)對(duì)傳輸信息進(jìn)行加密。Ron Rivest開(kāi)發(fā)了基于256字節(jié)的密鑰生成隨機(jī)數(shù)的RC4加密算法。這個(gè)算法非常簡(jiǎn)單,以至于幾分鐘內(nèi)你就可以記住它。
RC4從創(chuàng)建一個(gè)256字節(jié)的數(shù)組“S”開(kāi)始,并從0到255對(duì)其進(jìn)行填充。然后從“S”的第0位開(kāi)始循環(huán),將“S”和密鑰中的字節(jié)進(jìn)行混合,這樣做是為了創(chuàng)建用于產(chǎn)生“隨機(jī)”數(shù)的狀態(tài)機(jī)。為了生成隨機(jī)數(shù),我們將“S”數(shù)組進(jìn)行洗牌(譯注:參考百度百科RC4)
圖形化描述是這樣的:
對(duì)一個(gè)字節(jié)進(jìn)行加密,我們對(duì)偽隨機(jī)字節(jié)和要加密的字節(jié)進(jìn)行異或運(yùn)算。記住將一個(gè)比特和1進(jìn)行異或的話是使這個(gè)比特反轉(zhuǎn)(譯注:0^1=1, 1^1=0)。因?yàn)榍懊娈a(chǎn)生的是隨機(jī)數(shù),所以大約會(huì)有一半的比特碼會(huì)被反轉(zhuǎn),這種隨機(jī)的比特反轉(zhuǎn)在加密數(shù)據(jù)時(shí)非常有效。你已經(jīng)看到,這并不復(fù)雜,而且運(yùn)行起來(lái)很快。我想這也許就是Amazon用它的原因吧。
回想一下,我們有“client_write_key”和“server_write_key”。這意味這我們需要?jiǎng)?chuàng)建兩個(gè)RC4實(shí)例,一個(gè)用于加密瀏覽器發(fā)送的消息,另一個(gè)用于解密服務(wù)器返回的消息。.
“client_write”最前面的隨機(jī)字節(jié)是“E 20 7A 4D FE FB 78 A7 33 ...”,如果我們用這些字節(jié)和未加密的消息頭(經(jīng)查證,該消息的字節(jié)為“4 00 00 0C 98 F0 AE CB C4 ...”)進(jìn)行異或運(yùn)算的話,我們將得到在Wireshark中看到的已加密的部分:
服務(wù)器做的事情幾乎一樣。它發(fā)出一條“Change Cipher Spec”消息,然后發(fā)出的“Finished Message”消息,這條消息包括所有的“握手”消息,以及解密的客戶端發(fā)過(guò)來(lái)的“Finished Message”,這也向客戶端表明了服務(wù)端可以正確解密客戶端發(fā)過(guò)來(lái)的消息。
歡迎回到應(yīng)用層!
現(xiàn)在,220毫秒過(guò)去了,我們最終為應(yīng)用層準(zhǔn)備好了,現(xiàn)在我們可以發(fā)送通過(guò)TLS層使用RC4的寫(xiě)實(shí)例加密過(guò)的普通HTTP消息,也可以解密服務(wù)端RC4寫(xiě)實(shí)例發(fā)過(guò)來(lái)的消息。此外,TLS層還會(huì)通過(guò)計(jì)算消息內(nèi)容的HMAC_MD5哈希值來(lái)校驗(yàn)每一條消息是否被篡改。
至此,“握手”過(guò)程已經(jīng)完成,現(xiàn)在TLS記錄的content type變成23(0x17)。加密的數(shù)據(jù)流以“17 03 01”開(kāi)始,這幾個(gè)字節(jié)表明了記錄類型和TLS版本,后面是包含了HMAC哈希的加密數(shù)據(jù)。
對(duì)如下明文的加密:
GET /gp/cart/view.html/ref=pd_luc_mri HTTP/1.1
Host: www.amazon.com
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.0.10) Gecko/2009060911 Minefield/3.0.10 (.NET CLR 3.5.30729)
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive
...
將得到下面這些字節(jié):
剩下的唯一有趣的事是每個(gè)消息的序列號(hào)是依次遞增的,現(xiàn)在是1(下一個(gè)消息將會(huì)是2,以此類推)。
服務(wù)端做的事情是一樣的,不過(guò)它使用“server_write_key”這個(gè)密鑰。我們看到它的響應(yīng)消息,包括泄露秘密的應(yīng)用數(shù)據(jù)頭。
這個(gè)消息解密后得到:
HTTP/1.1 200 OK
Date: Wed, 10 Jun 2009 01:09:30 GMT
Server: Server
...
Cneonction: close
Transfer-Encoding: chunked
這是一個(gè)普通的HTTP返回消息,它包含一個(gè)非描述性“Server: Server”HTTP頭和一個(gè)來(lái)自Amazon負(fù)載均衡器的“Cneonction: close”頭,顯然拼寫(xiě)有誤。
TLS就在應(yīng)用層之下。HTTP服務(wù)器上的軟件可以就像發(fā)送非加密數(shù)據(jù)一樣工作,而唯一的區(qū)別是它們(指軟件)將數(shù)據(jù)寫(xiě)到一個(gè)庫(kù),由這個(gè)庫(kù)統(tǒng)一做加密。OpenSSL是TLS的一個(gè)非常流行的開(kāi)源庫(kù)。
在雙方發(fā)送和接受加密數(shù)據(jù)的過(guò)程中,鏈接一直保持活動(dòng)狀態(tài),直到任何一端發(fā)出一條“closure alert”消息并接著關(guān)閉連接。如果在斷開(kāi)后的很短時(shí)間內(nèi)重連,則可以重用前面協(xié)商好的密鑰(前提是服務(wù)器還緩存著他們),這樣就不需要公鑰操作,否則,就需要重新執(zhí)行一次完全的握手過(guò)程。
應(yīng)用數(shù)據(jù)消息可以是任何信息,這點(diǎn)很重要。“HTTPS”特別的唯一原因是因?yàn)閃eb太流行了,還有其他基于TCP/IP的協(xié)議運(yùn)行在TLS之上。例如,TLS也用于FTPS和SMTP的安全擴(kuò)展。使用TLS肯定比你自己發(fā)明解決方案要好,另外,使用經(jīng)得起仔細(xì)的安全分析的協(xié)議,你能從中獲益。
……順利完工!
TLS RFC中還包含很多我們這里遺漏的內(nèi)容,它是一份可讀性非常好的規(guī)范。我們覆蓋的內(nèi)容是對(duì)Firefox和Amazon之間的220毫秒的舞蹈進(jìn)行觀察所看到的一條路徑。這個(gè)過(guò)程很大程度 上受Amazon在ServerHello消息中所選擇的TLS_RSA_WITH_RC4_128_MD5密碼套件的影響,這是一個(gè)合理的選擇,因?yàn)樗鼘?duì)速度的傾向比對(duì)安全的傾向更多一點(diǎn)。
如我們所看到的,如果有人能將Amazon的模數(shù)“n”分解成“p”,“q”,那么他就可以有效解密所有的“安全”流通,直到Amazon換掉它的證書(shū)。所以Amazon通過(guò)每年替換一次證書(shū)的方式來(lái)平衡這方面的擔(dān)心。
其中有一個(gè)密碼套件是“TLS_DHE_RSA_WITH_AES_256_CBC_SHA”,它使用Diffie-Hellman密鑰交換算法,這個(gè)算法具有良好的 “正向安全”的特點(diǎn)。也就意味這如果某人破解了密碼交換的數(shù)學(xué)原理,對(duì)于解密下一個(gè)會(huì)話也沒(méi)有什么益處。這個(gè)算法的缺點(diǎn)是需要計(jì)算更大的數(shù)字,所以對(duì)于一個(gè)很忙的服務(wù)器來(lái)說(shuō)計(jì)算成本更大?!案呒?jí)加密標(biāo)準(zhǔn)”(AES)出現(xiàn)在我們提供的很多密碼套件中。它與RC4 的不同在于它一次加密16字節(jié)的“數(shù)據(jù)塊”而不是一個(gè)字節(jié),由于它的密鑰可以大到256比特,所以很多人認(rèn)為它比RC4要更安全。
僅需220毫秒中,網(wǎng)絡(luò)中兩個(gè)端點(diǎn)連接到一起,提供了足夠資料來(lái)信任對(duì)方,建立加密算法,并開(kāi)始進(jìn)行加密的信息傳輸。
我寫(xiě)了一個(gè)程序?qū)ξ恼轮兴峒暗奈帐謪f(xié)議走了一遍。