HTTPS连接的前几毫秒发生了什么
原文地址:http://blog.jobbole.com/48369/
提示:英文原文寫于2009年,當(dāng)時(shí)的Firefox和最新版的Firefox,界面也有很大改動(dòng)。以下是正文。
花了數(shù)小時(shí)閱讀了如潮的好評(píng),Bob最終迫不及待為他購買的托斯卡納全脂牛奶點(diǎn)擊了“進(jìn)行結(jié)算”,然后……
哇!剛剛發(fā)生了什么?
在點(diǎn)擊按鈕過后的220毫秒時(shí)間內(nèi),發(fā)生了一系列有趣的事情,火狐瀏覽器(Firefox)不僅改變了地址欄顏色,而且在瀏覽器的右下角出現(xiàn)了一個(gè)小鎖頭的標(biāo)志。在我最喜歡的互聯(lián)網(wǎng)工具Wireshark的幫助下,我們可以通過一個(gè)經(jīng)過略微調(diào)整的用于debug的火狐瀏覽器來探究這一過程。
根據(jù)RFC 2818標(biāo)準(zhǔn)(譯者注:RFC 2818為HTTP Over TLS-網(wǎng)絡(luò)協(xié)議),火狐瀏覽器自動(dòng)通過連接Amazon.com的443端口來響應(yīng)HTTPS請(qǐng)求。
很多人會(huì)把HTTPS和網(wǎng)景公司(Netscape)于上世紀(jì)九十年代中期創(chuàng)建的SSL(安全套接層)聯(lián)系起來。事實(shí)上,隨著時(shí)間的推移,這兩者之間的關(guān)系也慢慢淡化。隨著網(wǎng)景公司漸漸的失去市場(chǎng)份額,SSL的維護(hù)工作移交給了Internet工程任務(wù)組(IETF)。由網(wǎng)景公司發(fā)布的第一個(gè)版本被重新命名為TLS 1.0(安全傳輸層協(xié)議 1.0),并于1999年1月正式發(fā)布。考慮到TLS已經(jīng)發(fā)布了將近10年,如今已經(jīng)很難再見到真正的SSL通信了。
?
客戶端問候(Client Hello)
TLS將全部的通信以不同方式包裹為“記錄”(Records)。我們可以看到,從瀏覽器發(fā)出的第一個(gè)字節(jié)為0×16(十進(jìn)制的22),它表示了這是一個(gè)“握手”記錄。
接下來的兩個(gè)字節(jié)是0×0301,它表示了這是一條版本為3.1的記錄,同時(shí)也向我們表明了TLS1.0實(shí)際上是基于SSL3.1構(gòu)建而來的。
整個(gè)握手記錄被拆分為數(shù)條信息,其中第一條就是我們的客戶端問候(Client Hello),即0×01。在客戶端問候中,有幾個(gè)需要著重注意的地方:
- ?隨機(jī)數(shù):
在客戶端問候中,有四個(gè)字節(jié)以Unix時(shí)間格式記錄了客戶端的協(xié)調(diào)世界時(shí)間(UTC)。協(xié)調(diào)世界時(shí)間是從1970年1月1日開始到當(dāng)前時(shí)刻所經(jīng)歷的秒數(shù)。在這個(gè)例子中,0x4a2f07ca就是協(xié)調(diào)世界時(shí)間。在他后面有28字節(jié)的隨機(jī)數(shù),在后面的過程中我們會(huì)用到這個(gè)隨機(jī)數(shù)。
- SID(Session ID):
在這里,SID是一個(gè)空值(Null)。如果我們?cè)趲酌腌娭熬偷顷戇^了Amazon.com,我們有可能會(huì)恢復(fù)之前的會(huì)話,從而避免一個(gè)完整的握手過程。
- 密文族(Cipher Suites):
密文族是瀏覽器所支持的加密算法的清單。整個(gè)密文族是由推薦的加密算法“TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA”和33種其他加密算法所組成。別擔(dān)心其他的加密算法會(huì)出現(xiàn)問題,我們一會(huì)兒就會(huì)發(fā)現(xiàn)Amazon也沒有使用推薦的加密算法。
- ?Server_name擴(kuò)展:
通過這種方式,我們能夠告訴Amazon.com:瀏覽器正在試圖訪問https://www.amazon.com。這確實(shí)方便了很多,因?yàn)槲覀兊腡LS握手時(shí)間發(fā)生在HTTP通信之前,而HTTP請(qǐng)求會(huì)包含一個(gè)“Host頭”,從而使那些為了節(jié)約成本而將數(shù)百個(gè)網(wǎng)站域名解析到一個(gè)IP地址上的網(wǎng)絡(luò)托管商能夠分辨出一個(gè)網(wǎng)絡(luò)請(qǐng)求對(duì)應(yīng)的是哪個(gè)網(wǎng)站。傳統(tǒng)意義上的SSL同樣要求一個(gè)網(wǎng)站請(qǐng)求對(duì)應(yīng)一個(gè)IP地址,但是Server_name擴(kuò)展則允許服務(wù)器對(duì)瀏覽器的請(qǐng)求授予相對(duì)應(yīng)的證書。如果沒有其他的請(qǐng)求,Server_name擴(kuò)展應(yīng)該允許瀏覽器訪問這個(gè)IPV4地址一周左右的時(shí)間。
?
服務(wù)器問候(Server Hello)
Amazon.com回復(fù)的握手記錄由兩個(gè)比較大的包組成(2551字節(jié))。記錄中包含了0×0301的版本信息,意味著Amazon同意我們使用TLS1.0訪問的請(qǐng)求。這條記錄包含了三條有趣的子信息:
1.服務(wù)器問候信息(Server Hello)(2):
2.證書信息(11):
這段巨大的信息共有2464字節(jié),其證書允許客戶端在Amazon服務(wù)器上進(jìn)行認(rèn)證。這個(gè)證書其實(shí)并沒有什么奇特之處,你能通過瀏覽器瀏覽它的大部分內(nèi)容。
3.服務(wù)器問候結(jié)束信息(14):
這是一個(gè)零字節(jié)信息,用于告訴客戶端整個(gè)“問候”過程已經(jīng)結(jié)束,并且表明服務(wù)器不會(huì)再向客戶端詢問證書。
?
校驗(yàn)證書
此時(shí),瀏覽器已經(jīng)知道是否應(yīng)該信任Amazon.com。在這個(gè)例子中,瀏覽器通過證書確認(rèn)網(wǎng)站是否受信,它會(huì)檢查 Amazon.com 的證書,并且確認(rèn)當(dāng)前的時(shí)間是在“最早時(shí)間”2008年8月26日之后,在“最晚時(shí)間”2009年8月27日之前。瀏覽器還會(huì)確認(rèn)證書所攜帶的公共密鑰已被授權(quán)用于交換密鑰。
為什么我們要信任這個(gè)證書?
證書中所包含的簽名是一串非常長的大端格式的數(shù)字:
任何人都可以向我們發(fā)送這些字節(jié),但我們?yōu)槭裁匆湃芜@個(gè)簽名?為了解釋這個(gè)問題,我們首先要回顧一些重要的數(shù)學(xué)知識(shí):
RSA加密算法的基礎(chǔ)介紹
人人常常會(huì)問,編程和數(shù)學(xué)之間有什么聯(lián)系?證書就為數(shù)學(xué)在編程領(lǐng)域的應(yīng)用提供了一個(gè)實(shí)際的例子。Amazon的服務(wù)器告訴我們需要使用RSA算法來校驗(yàn)證書簽名。什么又是RSA算法呢?RSA算法是由麻省理工(MIT)的Ron Rivest、Adi Shamirh和Len Adleman(RSA命名各取了三人名字中的首字母)三人于上世紀(jì)70年代創(chuàng)建的。三位天才的學(xué)者結(jié)合了2000多年數(shù)學(xué)史上的精華,發(fā)明了這種簡潔高效的算法:
選取兩個(gè)較大的初值p和q,相乘得n;n = p*q ?接下來選取一個(gè)較小的數(shù)作為加密指數(shù)e,d作為解密指數(shù)是e的倒數(shù)。在加密的過程中,n和e是公開信息,解密密鑰d則是最高機(jī)密。至于p和q,你可以將他們公開,也可以作為機(jī)密保管。但是一定要記住,e和d是互為倒數(shù)的兩個(gè)數(shù)。
假設(shè)你現(xiàn)在有一段信息M(轉(zhuǎn)換成數(shù)字),將其加密只需要進(jìn)行運(yùn)算:C ≡ Me?(mod n)
這個(gè)公式表示M的e次冪,mod n表示除以n取余數(shù)。當(dāng)這段密文的接受者知道解密指數(shù)d的時(shí)候就可以將密文進(jìn)行還原:Cd?≡ (Me)d?≡ Me*d?≡ M1?≡ M (mod n)
有趣的是,解密指數(shù)d的持有者還可以將信息M進(jìn)行用解密指數(shù)d進(jìn)行加密:Md?≡ S (mod n)
加密者將S、M、e、n公開之后,任何人都可以獲得這段信息的原文:Se?≡ (Md)e?≡ Md*e?≡ Me*d?≡ M1?≡ M (mod n)
如同RSA的公共密鑰加密算法經(jīng)常被稱之為非對(duì)稱算法,因?yàn)榧用苊荑€(在我們的例子中為e)和解密密鑰(在我們的例子中是d)并不對(duì)稱。取余運(yùn)算的過程也不像我們平常接觸的運(yùn)算(諸如對(duì)數(shù)運(yùn)算)那樣簡單。RSA加密算法的神奇之處在于你可以非常快速的進(jìn)行數(shù)據(jù)的加密運(yùn)算,即 ,但是如果沒有解密密碼d,你將很難破解出密碼,即運(yùn)算 將不可能實(shí)現(xiàn)。正如我們所看到的,通過對(duì)n進(jìn)行因式分解而得到p和q,再推斷出解密密鑰d的過程難于上青天。
?
簽名驗(yàn)證
在使用RSA加密算法的時(shí)候,最重要的一條就是要確保任何涉及到的數(shù)字都要足夠復(fù)雜才能保證不被現(xiàn)有的計(jì)算方法所破解。這些數(shù)字要多復(fù)雜呢?Amazon.com的服務(wù)器是利用“VeriSign Class 3 Secure Server CA”來對(duì)證書進(jìn)行簽名的。從證書中,我們可以看到這個(gè)VeriSign(電子簽名校驗(yàn)器,也稱威瑞信公司)的系數(shù)n有2048位二進(jìn)制數(shù)構(gòu)成,換算成十進(jìn)制足足有617位數(shù)字:
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
(如果你想要對(duì)這一大串?dāng)?shù)字進(jìn)行分解因式獲得p和q,那就祝你好運(yùn)!順便一提,如果你真的計(jì)算出了p和q,那你就破解了Amazon.com數(shù)字簽名證書了!)
這個(gè)VeriSign的加密密鑰e是 。當(dāng)然,他們將解密密鑰d保管得十分嚴(yán)密,通常是在擁有視網(wǎng)膜掃描和荷槍實(shí)彈的警衛(wèi)守護(hù)的機(jī)房當(dāng)中。在簽名之前,VeriSign會(huì)根據(jù)相關(guān)約定的技術(shù)文檔,對(duì)Amazon.com證書上所提供的信息進(jìn)行校驗(yàn)。一旦證書信息符合相關(guān)要求,VeriSign會(huì)利用SHA-1哈希算法獲取證書的哈希值(hash),并對(duì)其進(jìn)行聲明。在Wireshark中,完整的證書信息會(huì)顯示在“signedCertificate”(已簽名證書)中:
這里應(yīng)該是軟件的用詞不當(dāng),因?yàn)檫@一段實(shí)際上是指那些即將被簽名的信息,而不是指那些已經(jīng)包含了簽名的信息。
實(shí)際上經(jīng)過簽名的信息S,在Wireshark中被稱之為“encrypted”(密文)。我們將S的e次冪除以n取余數(shù)(即公式: )就能計(jì)算出被加密的原文,其十六進(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 0906052B0E03021A05000414C19F8786 871775C60EFE0542 E4C2167C830539DB
根據(jù)PKCS#1 v1.5標(biāo)準(zhǔn)(譯者注:The Public-Key Cryptography Standards (PKCS)是由美國RSA數(shù)據(jù)安全公司及其合作伙伴制定的一組公鑰密碼學(xué)標(biāo)準(zhǔn))規(guī)定:“第一個(gè)字節(jié)是00,這樣就可以保證加密塊在被轉(zhuǎn)換為整數(shù)的時(shí)候比其加密參數(shù)要小。”第二個(gè)字節(jié)為01,表示了這是一個(gè)私有密鑰操作(數(shù)字簽名就是私有密鑰操作的一種)。后面緊接著的一連串的FF字節(jié)是為了填充數(shù)據(jù),使得這一串?dāng)?shù)字變得足夠大(加大黑客惡意破解的難度)。填充數(shù)字以一個(gè)00字節(jié)結(jié)束。緊接著的30 21 30 09 06 05 2B 0E 03 02 1A 05 00 04 14這些字節(jié)是PKCS#1 v2.1標(biāo)準(zhǔn)中用于說明這段哈希值是通過SHA-1算法計(jì)算而出的。最后的20字節(jié)是SHA-1算法所計(jì)算出來的哈希值,即對(duì)未加密信息的摘要描述。(譯者注:原文中這里使用了帶引號(hào)的signedCertificate,根據(jù)作者前文描述,這應(yīng)該是Wireshark軟件的bug,實(shí)際上應(yīng)指的是未被加密的信息。)
因?yàn)檫@段信息的格式正確,且最后的哈希值與我們獨(dú)立計(jì)算出來的校驗(yàn)一致,所以我們可以斷定,這一定是知道“VeriSign Class 3 Secure Server CA”的解密密鑰d的人對(duì)它進(jìn)行了簽名。而世界上只有VeriSign公司才知道這串密鑰。
當(dāng)然了,我們也可以重復(fù)驗(yàn)證這個(gè)“VeriSign Class 3 Secure Server CA”的證書的確是通過VeriSign公司的“第三類公私證書認(rèn)證(Class 3 Public Primary Certification Authority)”進(jìn)行簽名的。
但是,即便是這樣,我們?yōu)槭裁匆湃蜼eriSign公司?整個(gè)的信任鏈條就此斷掉了。
由圖可以看到,“VeriSign Class 3 Secure Server CA”對(duì)Amazon.com進(jìn)行了簽名,而“VeriSign Class 3 Public Primary Certification Authority”對(duì)“VeriSign Class 3 Secure Server CA”進(jìn)行了簽名,但是最頂部的“VeriSign Class 3 Public Primary Certification Authority”則對(duì)自己進(jìn)行了簽名。這是因?yàn)?#xff0c;這個(gè)證書自從NSS(網(wǎng)絡(luò)安全服務(wù))庫中的certdata.txt 升級(jí)到1.4版之后就作為“受信任的根證書頒發(fā)機(jī)構(gòu)”(譯者注:參照微軟官方翻譯)被編譯到了Mozilla產(chǎn)品中(火狐瀏覽器)。這段信息是由網(wǎng)景公司的Robert Relyea于2000年9月6日提交的,并隨附以下注釋:
“由僅存的NSS編譯了框架。包含一個(gè)在線的certdata.txt文檔,其中包含了我們受信的跟證書頒發(fā)機(jī)構(gòu)(一旦我們獲得了其他受信機(jī)構(gòu)的許可會(huì)陸續(xù)將他們添加進(jìn)去)”。
這個(gè)舉動(dòng)有著相當(dāng)長遠(yuǎn)的影響,因?yàn)檫@些證書的有效日期是從1996年1月28日到2028年1月1日。
肯·湯普遜(Ken Thompson)在他的《對(duì)深信不疑的信任》(譯者注:Reflections on Trusting Trust是肯湯普遜1983年獲得圖靈獎(jiǎng)時(shí)的演說)的演說中解釋的很好:你最終還是要絕對(duì)信任某一人,在這個(gè)問題上沒有第二條路可走。在本文的例子中,我們就毫無保留的信任Robert Relyea做了一個(gè)正確的決定。我們同樣希望Mozilla在自己軟件中加入“受信任根證書頒發(fā)機(jī)構(gòu)”這種行為也是合理的吧。
這里需要注意的是:這一系列的證書和簽名只是用來形成一個(gè)信任鏈。在公共互聯(lián)網(wǎng)上,VeriSign的根證書被火狐瀏覽器完全信任的時(shí)間遠(yuǎn)早于你接觸互聯(lián)網(wǎng)。在一個(gè)公司中,你可以創(chuàng)建自己的受信任的根證書頒發(fā)機(jī)構(gòu)并把它安裝到任何人的計(jì)算機(jī)中。
相對(duì)的,你也可以購買VeriSign公司的業(yè)務(wù),降低整個(gè)證書信任鏈的信任風(fēng)險(xiǎn)。通過第三方的認(rèn)證機(jī)構(gòu)(在這個(gè)例子里是VeriSign公司)我們能利用證書建立起信任關(guān)系。如果你有類似于“悄悄話”的安全途徑來傳遞一個(gè)秘密的key,那你也可以使用一個(gè)預(yù)共享密鑰(PSK)來建立起信任關(guān)系。諸如TLS-PSK、或者帶有安全遠(yuǎn)程密碼(SRP)的TLS擴(kuò)展包都能讓我們使用預(yù)共享密鑰。不行的是,這些擴(kuò)展包在應(yīng)用和支持方面遠(yuǎn)遠(yuǎn)比不上TLS,所以他們有的時(shí)候并不實(shí)用。另外,這些替代選項(xiàng)需要額外德爾安全途徑進(jìn)行保密信息的傳輸,這一部分的開銷遠(yuǎn)比我們現(xiàn)在正在應(yīng)用的TLS龐大。換句話說,這也就是我們?yōu)槭裁床粦?yīng)用那些其他途徑構(gòu)建信任關(guān)系的原因。
言歸正傳,我們所需要的最后確認(rèn)的信息就是在證書上的主機(jī)名跟我們預(yù)想的是一樣的。Nelson Bolyard在SSL_AuthCertificate 函數(shù)中的注釋為我們解釋其中的原因:
“SSL連接的客戶端確認(rèn)證書正確,并檢查證書中所對(duì)應(yīng)的主機(jī)名是否正確,因?yàn)檫@是我們應(yīng)對(duì)中間人攻擊的唯一方式!” (譯者注:中間人攻擊是一種“間接”的入侵攻擊,這種攻擊模式是通過各種技術(shù)手段將受入侵者控制的一臺(tái)計(jì)算機(jī)虛擬放置在網(wǎng)絡(luò)連接中的兩臺(tái)通信計(jì)算機(jī)之間,這臺(tái)計(jì)算機(jī)就稱為“中間人”。)
/* cert is OK. This is the client side of an SSL connection.* Now check the name field in the cert against the desired hostname.* NB: This is our only defense against Man-In-The-Middle (MITM) attacks! */這樣的檢查是為了防止中間人攻擊:因?yàn)槲覀儗?duì)整個(gè)信任鏈條上的人都采取了完全信任的態(tài)度,認(rèn)為他們并不會(huì)進(jìn)行黑客行為,就像我們的證書中所聲稱它是來自Amazon.com,但是假如他的真實(shí)來源并非Amazon.com,那我們可能就有被攻擊的危險(xiǎn)。如果攻擊者使用域名污染(DNS cache poisoning)等技術(shù)對(duì)你的DNS服務(wù)器進(jìn)行篡改,那么你也許會(huì)把黑客的網(wǎng)站誤認(rèn)為是一個(gè)安全的受信網(wǎng)站(諸如Amazon.com),因?yàn)榈刂窓陲@示的信息一切正常。這最后一步對(duì)證書頒發(fā)機(jī)構(gòu)的檢查就是為了防止這樣的事情發(fā)生。
?
隨機(jī)密碼串(Pre-Master Secret)
現(xiàn)在我們已經(jīng)了解了Amazon.com的各項(xiàng)要求,并且知道了公共解密密鑰e和參數(shù)n。在通信過程中的任何一方也都知道了這些信息(佐證就是我們通過Wireshark獲得了這些信息)。現(xiàn)在我們所需要做的事情就是生成一串竊密者/攻擊者都不能知道的隨機(jī)密碼。這并不像聽上去的那么簡單。早在1996年,研究人員就發(fā)現(xiàn)了網(wǎng)景瀏覽器1.1的偽隨機(jī)數(shù)發(fā)生器僅僅利用了三個(gè)參數(shù):當(dāng)天的時(shí)間,進(jìn)程ID和父進(jìn)程ID。正如研究人員所指出的問題:這些用于生成隨機(jī)數(shù)的參數(shù)并不具有隨機(jī)性,而且他們相對(duì)來說比較容易被破解。
因?yàn)橐磺卸际莵碓从谶@三個(gè)隨機(jī)數(shù)參數(shù),所以在1996,利用當(dāng)時(shí)的機(jī)器僅需要25秒鐘的時(shí)間就可以破解一個(gè)SSL通信。找到一種生成真正隨機(jī)數(shù)的方法是非常困難的,如果你不相信這一點(diǎn),那就去問問Debian OpenSSL的維護(hù)工程師吧。如果隨機(jī)數(shù)的生成方式遭到破解,那么建立在這之上的一系列安全措施都是毫無意義的。
在Windows操作系統(tǒng)中,用于加密目的隨機(jī)數(shù)都是利用一個(gè)叫做CryptGenRandom的函數(shù)生成的。這個(gè)函數(shù)的哈希表位對(duì)超過125個(gè)來源的數(shù)據(jù)進(jìn)行抽樣!火狐瀏覽器利用CryptGenRandom函數(shù)和它自身的函數(shù)來構(gòu)成它自己的偽隨機(jī)數(shù)發(fā)生器。(譯者注:之所以稱之為偽隨機(jī)數(shù)是因?yàn)檎嬲饬x上的隨機(jī)數(shù)算法并不存在,這些函數(shù)還是利用大量的時(shí)變、量變參數(shù)來通過復(fù)雜的運(yùn)算生成相對(duì)意義上的隨機(jī)數(shù),但是這些數(shù)之間還是存在統(tǒng)計(jì)學(xué)規(guī)律的,只是想要找到生成隨機(jī)數(shù)的過程并不那么容易)。
我們并不會(huì)直接利用生成的這48字節(jié)的隨機(jī)密碼串,但是由于很多重要的信息都是由他計(jì)算而來的,所以對(duì)隨機(jī)密碼串的保密就顯得格外重要。正如我之前所預(yù)料到的,火狐瀏覽器對(duì)隨機(jī)密碼串的保密十分嚴(yán)格,所以我不得不編譯了一個(gè)用于debug的版本。為了觀察隨機(jī)密碼串,我還特地設(shè)置了SSLDEBUGFILE和SSLTRACE兩個(gè)環(huán)境變量。
其中,SSLDEBUGFILE顯示的就是隨機(jī)密碼串的值:
| 1 2 3 4 | 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; |
需要注意的是,這串?dāng)?shù)字從各種意義上來說都不是真正的隨機(jī)數(shù),就拿它的前兩位來說:這就是根據(jù)TLS協(xié)議約定的TLS版本號(hào)(0301)。
?
密碼交換(Trading Secret)
我們現(xiàn)在需要做的就是計(jì)算出Amazon.com所要求的密碼。因?yàn)锳mazon.com希望使用“TLS_RSA_WITH_RC4_128_MD5”加密組,所以我們使用RSA加密算法進(jìn)行這一過程。你可以將這48字節(jié)的隨機(jī)密碼串作為初始參數(shù),但是根據(jù)公共密鑰密碼標(biāo)準(zhǔn)(PKCS)#1 v1.5中的注釋,我們需要用隨機(jī)數(shù)據(jù)將隨機(jī)密碼串填充到實(shí)際要求的參數(shù)大小(1024位二進(jìn)制/128字節(jié))。這樣的話攻擊者想要破解我們的隨機(jī)密碼串就難上加難了。這也是我們保障自己安全的最后一道防線,以防我們?cè)谇懊娴牟襟E中犯了諸如重復(fù)使用密碼這樣的低級(jí)錯(cuò)誤。如果我們重復(fù)使用了隨機(jī)密碼串,由于使用了隨機(jī)數(shù)填充,竊密者在網(wǎng)絡(luò)中攔截的也會(huì)是兩個(gè)不同的值。
同樣的,我們很難直接觀察到火狐瀏覽器中的這一過程,所以我不得不在填充隨機(jī)數(shù)的函數(shù)中增加了debug的語句,使我們能夠觀察這一過程:
| 1 2 3 4 5 6 7 8 | wrapperHandle = fopen("plaintextpadding.txt", "a"); fprintf(wrapperHandle, "PLAINTEXT = "); for(i = 0; i < modulusLen; i++) { ????fprintf(wrapperHandle, "%02X ", block[i]); } fprintf(wrapperHandle, "\r\n"); fclose(wrapperHandle); |
在這個(gè)例子中,完整的填充后的隨機(jī)密碼串為:
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 1C0A B1 95 50 29 BE 02 AD E6 AD 6E 11 3F20 C4 66 F0 64 22 57 7E E1 06 7A 3B
火狐瀏覽器使用這個(gè)值計(jì)算出 ,我們可以看到它顯示在“客戶端交換密鑰”(Client Key Exchange)的記錄中:
在這個(gè)過程的最后,火狐瀏覽器會(huì)發(fā)送一個(gè)不加密的信息:一條“Change Cipher Spec”記錄:
通過這種方式:火狐瀏覽器要求Amazon.com在后面的通信過程中使用約定的加密方式傳輸信息。
?
獲得主密鑰(Master Secret)
如果我們正確完成了之前的過程,并且各方都獲得了48字節(jié)(256二進(jìn)制位)的隨機(jī)密碼串。從Amazon.com的角度來看,這里還有一些信任問題:隨機(jī)密碼串是由客戶端生成的,并沒有將任何服務(wù)器信息或者之前約定的信息加入其中。這一點(diǎn),我們會(huì)通過生成主密鑰的方式加以完善。根據(jù)協(xié)議規(guī)范約定,這個(gè)的計(jì)算過程為:
| 1 | master_secret = PRF(pre_master_secret, "master secret", ClientHello.random + ServerHello.random) |
pre_master_secret就是我們之前傳送的隨機(jī)密碼串,”master secret”是一串ASCII碼(例如:6d 61 73 74 65 72……),再連接上在客戶端問候和服務(wù)器問候(來自Amazon的)的信息。
PRF是在規(guī)范中約定的偽隨機(jī)函數(shù),它將密鑰、ASCII碼標(biāo)簽、哈希值整合在一起。各有一半的參數(shù)分別使用MD5和SHA-1獲取哈希值。這是一種十分明智的做法,即使是想要單單破解相對(duì)簡單MD5和SHA-1也不是那么容易的事情。而且這個(gè)函數(shù)會(huì)將返回值傳給自身直至迭代到我們需要的位數(shù)。
利用這個(gè)函數(shù),我們生成了48字節(jié)的主密鑰:
4C AF 20 30 8F4C 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
?
生成各種密鑰
現(xiàn)在,各方面已經(jīng)有了主密鑰,根據(jù)協(xié)議約定,我們需要利用PRF生成這個(gè)會(huì)話中所需要的各種密鑰,稱之為“密鑰塊”(key block):
| 1 | key_block = PRF(SecurityParameters.master_secret, "key expansion", SecurityParameters.server_random + SecurityParameters.client_random); |
密鑰塊用于構(gòu)成以下密鑰:
| 1 2 3 4 5 6 | 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] |
因?yàn)槲覀兪褂昧祟愃朴诟呒?jí)加密標(biāo)準(zhǔn)(AES)的密碼流代替了分組密碼我們就不需要初始化向量(IVs)了。因此我們只需要雙方的兩個(gè)16字節(jié)(128二進(jìn)制位)的消息認(rèn)證碼(Message Authentication Code,MAC),因?yàn)镸D5的哈希值就是16字節(jié)的。此外,雙方也需要16字節(jié)(128二進(jìn)制位)的RC4碼。所以我們總共需要從密碼塊獲得2*16 + 2*16 = 64字節(jié)的數(shù)據(jù)。
運(yùn)行PRF,我們能得到以下值:
| 1 2 3 4 | 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)備加密!
客戶端最后一次送出的握手信息是“結(jié)束信息”。這條信息保證了沒有人篡改握手信息,并且我們已經(jīng)知曉所必須的密鑰。客戶端將整個(gè)握手過程的全部信息都放入一個(gè)名為“handshake_messages”的緩沖區(qū)。我們能通過偽隨機(jī)函數(shù)利用主密鑰、“client finished”標(biāo)簽、MD5和SHA-1的哈希值生成12字節(jié)的“區(qū)別數(shù)據(jù)”(verify_data):
| 1 | verify_data = PRF(master_secret, "client finished", MD5(handshake_messages) + SHA-1(handshake_messages)) [12] |
我們?cè)谶@個(gè)結(jié)果前面加上0×14(用于表示結(jié)束信息)和00 00 0c(用于表示verify_data 有12字節(jié))。就像以后所有的加密過程一樣,我們要在加密之前確保原始數(shù)據(jù)沒有被篡改。因?yàn)槲覀兪褂玫氖恰癟LS_RSA_WITH_RC4_128_MD5”密碼組,這就意味著我們需要使用MD5哈希函數(shù)。
有些人一聽到MD5函數(shù)就會(huì)嗤之以鼻,因?yàn)槠渥陨淼拇_存在一些缺陷。我自己當(dāng)然也不會(huì)推薦這種算法。但是TLS的聰明之處就在于他并不直接使用MD5函數(shù),只是利用哈希值的版本來校驗(yàn)數(shù)據(jù)。只就意味著我們并未直接應(yīng)用到MD5(m):
HMAC_MD5(Key, m) = MD5((Key ⊕ opad) ++ MD5((Key ⊕ ipad) ++ m)
(其中,⊕表示的是異或運(yùn)算)
在實(shí)際中:
HMAC_MD5(client_write_MAC_secret, seq_num + TLSCompressed.type + TLSCompressed.version + TLSCompressed.length + TLSCompressed.fragment));
正如你所見,我們?cè)诤瘮?shù)中使用了一個(gè)根據(jù)明文(在這里明文叫做“TLSCompressed”)編號(hào)的序號(hào)(seq_num)。這個(gè)序號(hào)的作用就是為了阻止攻擊者在數(shù)據(jù)流中間插入之前被其截獲的信息。如果發(fā)生了這樣的攻擊,序號(hào)就能清楚的警告我們數(shù)據(jù)中的異常。同樣的,這個(gè)序號(hào)也能幫助我們發(fā)現(xiàn)攻擊者從數(shù)據(jù)流中剔除的數(shù)據(jù)。
剩下的工作只剩下啊加密這些數(shù)據(jù)了!
?
RC4加密
我們之前協(xié)商過的密碼組是“TLS_RSA_WITH_RC4_128_MD5”。這就意味著我們需要使用RC4(Ron`s code 4)加密規(guī)則進(jìn)行數(shù)據(jù)流的加密。羅納德李威斯特(Ron Rivest)開發(fā)了這種基于一個(gè)256字節(jié)的Key產(chǎn)生隨機(jī)加密效果的算法。這個(gè)算法簡單到你幾分鐘就能記住。
首先,RC4生成一個(gè)256字節(jié)的數(shù)組S,并用0-255填充。接下來的工作就是將需要將KEY混合插入進(jìn)數(shù)組中并反復(fù)迭代。你可以編寫一個(gè)狀態(tài)機(jī),利用它來闡釋隨機(jī)字節(jié)。為了產(chǎn)生隨機(jī)字節(jié),我們需要將S數(shù)組打亂,如圖所示:
為了加密一個(gè)字節(jié),我們將其與隨機(jī)字節(jié)進(jìn)行異或運(yùn)算。記住:一位二進(jìn)制數(shù)與1作異或運(yùn)算會(huì)翻轉(zhuǎn)(譯者注:即1^1=0;1^0=1)。因?yàn)槲覀兝玫氖请S機(jī)數(shù),所以從統(tǒng)計(jì)學(xué)的角度來講,有一半的數(shù)被翻轉(zhuǎn)。這種隨機(jī)翻轉(zhuǎn)的現(xiàn)象就是我們加密數(shù)據(jù)的有效方法。正如你所見,這并不復(fù)雜,而且計(jì)算速度十分快,我認(rèn)為這也是Amazon.com選擇它的原因之一。
記得我們有“client_write_key”和“server_write_key”嗎?這就意味我們需要兩個(gè)RC4實(shí)例:一個(gè)用來加密瀏覽器向服務(wù)器傳送的數(shù)據(jù),一個(gè)用來解密服務(wù)器向?yàn)g覽器傳送的數(shù)據(jù)。
“client_write_key”最初的幾個(gè)字節(jié)是7E 20 7A 4D FE FB 78 A7 33 …如果我們對(duì)這些字節(jié)和未加密的數(shù)據(jù)頭以及版本信息(“14 00 00 0C98 F0 AE CB C4 …”)進(jìn)行異或運(yùn)算,我們就能得到在Wireshark中看到的加密信息了:
服務(wù)器端做的幾乎是相同的事情。它們發(fā)送了一個(gè)密鑰協(xié)議的說明和一個(gè)包含全部握手過程的結(jié)束信息,其中有結(jié)束信息的解密版本。因此,這種機(jī)制就保證了客戶端和服務(wù)器能成功的解密信息。
?
歡迎來到應(yīng)用層!
現(xiàn)在,從我們點(diǎn)擊了按鈕之后已經(jīng)過去了220毫秒,我們終于為應(yīng)用層做好了準(zhǔn)備!現(xiàn)在,我們發(fā)送的普通的HTTP數(shù)據(jù)流會(huì)通過TLS層的加密實(shí)例進(jìn)行加密,在服務(wù)器的解密實(shí)例進(jìn)行解密。而且TLS會(huì)對(duì)數(shù)據(jù)進(jìn)行哈希校驗(yàn),以保證數(shù)據(jù)內(nèi)容的準(zhǔn)確性。
在這個(gè)時(shí)候,整個(gè)的握手過程就結(jié)束了。我們的TLS記錄內(nèi)容現(xiàn)在有了23條(0×17)。加密數(shù)據(jù)以“17 03 01”開頭,表示了記錄類型和TLS版本,后面緊跟著加密數(shù)據(jù)的大小和哈希校驗(yàn)值。
加密的數(shù)據(jù)的明文如下:
| 1 2 3 4 5 6 7 8 9 10 | 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 ... |
在Wireshark中顯示如下:
唯一有趣的地方是序號(hào)是按照記錄來增長,這條記錄是1,下一條就是2。
服務(wù)器端利用“server_write_key”做著同樣的事情。我們能看到服務(wù)器的相應(yīng)結(jié)果,包括程序開頭的指示位:
解密后的信息如下:
| 1 2 3 4 5 6 | HTTP/1.1 200 OK Date: Wed, 10 Jun 2009 01:09:30 GMT Server: Server ... Cneonction: close Transfer-Encoding: chunked |
這就是一個(gè)來自Amazon負(fù)載平衡服務(wù)器的普通HTTP回應(yīng):包含了非描述性的服務(wù)器信息“Server: Server”和一個(gè)拼錯(cuò)了的“Cneonction: close”。
TLS層在應(yīng)用層的下面,所以軟件和服務(wù)器能夠像正常的HTTP傳輸那樣進(jìn)行工作,唯一的區(qū)別就是傳輸?shù)臄?shù)據(jù)會(huì)被TLS層進(jìn)行加密。
OpenSSL是一個(gè)應(yīng)用很廣的TLS開源庫。
整個(gè)連接會(huì)一直保持,除非有一方提出了“關(guān)閉警告(closure alert)”并且關(guān)閉了連接。如果我們?cè)谶B接斷開后的短時(shí)間內(nèi)再次提出連接請(qǐng)求,我們可以使用之前使用過的key來進(jìn)行連接,從而避免一次新的握手過程。(這個(gè)要取決于服務(wù)器端key的有效時(shí)間。)
需要注意的是:應(yīng)用程序可以發(fā)送任何數(shù)據(jù),但是HTTPS的特殊之處在于WEB應(yīng)用的廣泛普及。要知道還有非常多的基于TCP/IP并且使用TLS進(jìn)行數(shù)據(jù)加密的協(xié)議(如FTPS,sSMTP)。使用TLS要比你自己發(fā)明一種是數(shù)據(jù)加密方案便捷的多。況且,你所使用的安全協(xié)議一定要足夠安全。
?
…完工!
TLS RFC的文檔包含了更多的信息,有需要的朋友們可以自己查閱,我們?cè)谶@里只是簡單的介紹了其中的過程和原理,觀察了這220毫秒內(nèi)發(fā)生在火狐瀏覽器和Amazon服務(wù)器之間發(fā)生的故事:由Amazon.com基于速度和安全的綜合考慮選擇的“TLS_RSA_WITH_RC4_128_MD5”密碼組在HTTPS連接建立過程中的全部流程。
正如我們所看到的那樣,如果有人能對(duì)Amazon服務(wù)器的參數(shù)n進(jìn)行因式分解得到p和q的話,那他就能破解全部的基于亞馬遜證書的安全通信。所以Amazon為這個(gè)參數(shù)設(shè)置了有效期以防止這種事情的發(fā)生:
在我們提供的密碼族中,有一組密碼組“TLS_DHE_RSA_WITH_AES_256_CBC_SHA”使用了Diffie-Hellman密鑰交換,并因此能提供良好的前向安全特性。這就意味著如果有人破解了交換密鑰的數(shù)學(xué)運(yùn)算方式,他們也不能利用這個(gè)來破解其他的會(huì)話。但是他的一個(gè)劣勢(shì)在于其運(yùn)算需求更大的數(shù)字和更高的運(yùn)算能力。AES算法在很多密碼組中都出現(xiàn)了,它與RC4的不同之處在于它每次使用的是16字節(jié)的“塊”而RC4使用的是單字節(jié)。因?yàn)槠鋕ey最高能到256位二進(jìn)制位,所以一般認(rèn)為它比RC4的安全性更高。
在短短的220毫秒的時(shí)間里,兩個(gè)節(jié)點(diǎn)通過互聯(lián)網(wǎng)連接起來,并且利用一系列手段建立起了互信機(jī)制,構(gòu)建了加密算法,進(jìn)行加密數(shù)據(jù)的傳輸。
正是因?yàn)槿绱?#xff0c;我們故事的主人公才能在Amazon上買到他想要的牛奶!
(譯者注:作者所有相關(guān)的程序已經(jīng)提交到Github上,地址:https://github.com/moserware/TLS-1.0-Analyzer/tree/master)
轉(zhuǎn)載于:https://www.cnblogs.com/AloneSword/p/4676571.html
總結(jié)
以上是生活随笔為你收集整理的HTTPS连接的前几毫秒发生了什么的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ASP.NET MVC中如何实现页面跳转
- 下一篇: (FFOS Gaia) Telemetr