互聯網的通訊安全,創建在SSL/TLS協議之上。git
本文簡要介紹SSL/TLS協議的運行機制。文章的重點是設計思想和運行過程,不涉及具體的實現細節。若是想了解這方面的內容,請參閱RFC文檔。github
1、做用web
不使用SSL/TLS的HTTP通訊,就是不加密的通訊。全部信息明文傳播,帶來了三大風險。算法
(1) 竊聽風險(eavesdropping):第三方能夠獲知通訊內容。編程
(2) 篡改風險(tampering):第三方能夠修改通訊內容。瀏覽器
(3) 冒充風險(pretending):第三方能夠冒充他人身份參與通訊。安全
SSL/TLS協議是爲了解決這三大風險而設計的,但願達到:服務器
(1) 全部信息都是加密傳播,第三方沒法竊聽。
(2) 具備校驗機制,一旦被篡改,通訊雙方會馬上發現。
(3) 配備身份證書,防止身份被冒充。
互聯網是開放環境,通訊雙方都是未知身份,這爲協議的設計帶來了很大的難度。並且,協議還必須可以經受全部匪夷所思的攻擊,這使得SSL/TLS協議變得異常複雜。
2、歷史
互聯網加密通訊協議的歷史,幾乎與互聯網同樣長。
1994年,NetScape公司設計了SSL協議(Secure Sockets Layer)的1.0版,可是未發佈。
1995年,NetScape公司發佈SSL 2.0版,很快發現有嚴重漏洞。
1996年,SSL 3.0版問世,獲得大規模應用。
1999年,互聯網標準化組織ISOC接替NetScape公司,發佈了SSL的升級版TLS 1.0版。
2006年和2008年,TLS進行了兩次升級,分別爲TLS 1.1版和TLS 1.2版。最新的變更是2011年TLS 1.2的修訂版。
目前,應用最普遍的是TLS 1.0,接下來是SSL 3.0。可是,主流瀏覽器都已經實現了TLS 1.2的支持。
TLS 1.0一般被標示爲SSL 3.1,TLS 1.1爲SSL 3.2,TLS 1.2爲SSL 3.3。
3、基本的運行過程
SSL/TLS協議的基本思路是採用公鑰加密法,也就是說,客戶端先向服務器端索要公鑰,而後用公鑰加密信息,服務器收到密文後,用本身的私鑰解密。
可是,這裏有兩個問題。
(1)如何保證公鑰不被篡改?
解決方法:將公鑰放在數字證書中。只要證書是可信的,公鑰就是可信的。
(2)公鑰加密計算量太大,如何減小耗用的時間?
解決方法:每一次對話(session),客戶端和服務器端都生成一個"對話密鑰"(session key),用它來加密信息。因爲"對話密鑰"是對稱加密,因此運算速度很是快,而服務器公鑰只用於加密"對話密鑰"自己,這樣就減小了加密運算的消耗時間。
所以,SSL/TLS協議的基本過程是這樣的:
(1) 客戶端向服務器端索要並驗證公鑰。
(2) 雙方協商生成"對話密鑰"。
(3) 雙方採用"對話密鑰"進行加密通訊。
上面過程的前兩步,又稱爲"握手階段"(handshake)。
4、握手階段的詳細過程
"握手階段"涉及四次通訊,咱們一個個來看。須要注意的是,"握手階段"的全部通訊都是明文的。
4.1 客戶端發出請求(ClientHello)
首先,客戶端(一般是瀏覽器)先向服務器發出加密通訊的請求,這被叫作ClientHello請求。
在這一步,客戶端主要向服務器提供如下信息。
(1) 支持的協議版本,好比TLS 1.0版。
(2) 一個客戶端生成的隨機數,稍後用於生成"對話密鑰"。
(3) 支持的加密方法,好比RSA公鑰加密。
(4) 支持的壓縮方法。
這裏須要注意的是,客戶端發送的信息之中不包括服務器的域名。也就是說,理論上服務器只能包含一個網站,不然會分不清應該向客戶端提供哪個網站的數字證書。這就是爲何一般一臺服務器只能有一張數字證書的緣由。
對於虛擬主機的用戶來講,這固然很不方便。2006年,TLS協議加入了一個Server Name Indication擴展,容許客戶端向服務器提供它所請求的域名。
4.2 服務器迴應(SeverHello)
服務器收到客戶端請求後,向客戶端發出迴應,這叫作SeverHello。服務器的迴應包含如下內容。
(1) 確認使用的加密通訊協議版本,好比TLS 1.0版本。若是瀏覽器與服務器支持的版本不一致,服務器關閉加密通訊。
(2) 一個服務器生成的隨機數,稍後用於生成"對話密鑰"。
(3) 確認使用的加密方法,好比RSA公鑰加密。
(4) 服務器證書。
除了上面這些信息,若是服務器須要確認客戶端的身份,就會再包含一項請求,要求客戶端提供"客戶端證書"。好比,金融機構每每只容許認證客戶連入本身的網絡,就會向正式客戶提供USB密鑰,裏面就包含了一張客戶端證書。
4.3 客戶端迴應
客戶端收到服務器迴應之後,首先驗證服務器證書。若是證書不是可信機構頒佈、或者證書中的域名與實際域名不一致、或者證書已通過期,就會向訪問者顯示一個警告,由其選擇是否還要繼續通訊。
若是證書沒有問題,客戶端就會從證書中取出服務器的公鑰。而後,向服務器發送下面三項信息。
(1) 一個隨機數。該隨機數用服務器公鑰加密,防止被竊聽。
(2) 編碼改變通知,表示隨後的信息都將用雙方商定的加密方法和密鑰發送。
(3) 客戶端握手結束通知,表示客戶端的握手階段已經結束。這一項同時也是前面發送的全部內容的hash值,用來供服務器校驗。
上面第一項的隨機數,是整個握手階段出現的第三個隨機數,又稱"pre-master key"。有了它之後,客戶端和服務器就同時有了三個隨機數,接着雙方就用事先商定的加密方法,各自生成本次會話所用的同一把"會話密鑰"。
至於爲何必定要用三個隨機數,來生成"會話密鑰",dog250解釋得很好:
"無論是客戶端仍是服務器,都須要隨機數,這樣生成的密鑰纔不會每次都同樣。因爲SSL協議中證書是靜態的,所以十分有必要引入一種隨機因素來保證協商出來的密鑰的隨機性。
對於RSA密鑰交換算法來講,pre-master-key自己就是一個隨機數,再加上hello消息中的隨機,三個隨機數經過一個密鑰導出器最終導出一個對稱密鑰。
pre master的存在在於SSL協議不信任每一個主機都能產生徹底隨機的隨機數,若是隨機數不隨機,那麼pre master secret就有可能被猜出來,那麼僅適用pre master secret做爲密鑰就不合適了,所以必須引入新的隨機因素,那麼客戶端和服務器加上pre master secret三個隨機數一同生成的密鑰就不容易被猜出了,一個僞隨機可能徹底不隨機,但是是三個僞隨機就十分接近隨機了,每增長一個自由度,隨機性增長的可不是一。"
此外,若是前一步,服務器要求客戶端證書,客戶端會在這一步發送證書及相關信息。
4.4 服務器的最後迴應
服務器收到客戶端的第三個隨機數pre-master key以後,計算生成本次會話所用的"會話密鑰"。而後,向客戶端最後發送下面信息。
(1)編碼改變通知,表示隨後的信息都將用雙方商定的加密方法和密鑰發送。
(2)服務器握手結束通知,表示服務器的握手階段已經結束。這一項同時也是前面發送的全部內容的hash值,用來供客戶端校驗。
至此,整個握手階段所有結束。接下來,客戶端與服務器進入加密通訊,就徹底是使用普通的HTTP協議,只不過用"會話密鑰"加密內容。
5、參考連接
- MicroSoft TechNet, SSL/TLS in Detail
- Jeff Moser, The First Few Milliseconds of an HTTPS Connection
- Wikipedia, Transport Layer Security
- StackExchange, How does SSL work?
(完)
west 說:
好文。全面而易懂
2014年2月 5日 20:09 | # | 引用
李狗蛋 說:
壞蛋總不放過任何一絲作惡的機會,太多不要臉的運營商在鏈路劫持強插廣告,直接修改用戶的HTTP數據包,再就是NSA之流肆無忌憚的竊聽
發現一個HTTPS有意思的地方,只要53端口數據被轉發,無論域名對應的DNS解析IP是否是域名真實IP,只要最後都是53端口轉發到真實IP之上,就不會彈HTTPS證書錯誤
好比 https://a.com 對應 ipa 不通
那麼劫持DNS解析 https://a.com 到 ipb上 (ipb是通的)
只要在ipb上設置 ipb:53轉發到 ipa:53
這樣訪問 https://a.com 就通了,並且沒證書錯誤
2014年2月 5日 20:10 | # | 引用
Niclau 說:
啓用Server Name Indication擴展後,第一步客戶端發送請求,同時明文發送域名到server?
2014年2月 6日 11:32 | # | 引用
古明地戀 說:
您好,我有一個疑問。
第一步是用服務器公鑰加密的。而服務器公鑰包含在證書中。可是若是入侵者獲取到服務器證書,並用於解密以後的key,再用key來解密通訊內容,這樣怎麼防範?
2014年2月 6日 15:57 | # | 引用
Barret Lee 說:
阮老師寫的文章都是鞭辟入裏啊,通常是站在那些角度去闡述一個觀點或者描述一個事物呢?
2014年2月 6日 23:38 | # | 引用
harchiko 說:
Smart !智慧的發明!!
2014年2月 7日 22:21 | # | 引用
魂魄妖夢 說:
服務器證書只包含公鑰,沒法解密key。解密須要用私鑰。
私鑰通常放在server端。
若是能拿到私鑰,基本上能夠確定被入侵了。
這時候獲取私鑰都不算個事了你說是不。
2014年2月 8日 00:10 | # | 引用
lucas 說:
阮兄的文章很是值得一讀,簡潔又能把事情的前因後果講的清清楚楚的,不簡單。
2014年2月 8日 09:47 | # | 引用
CJey 說:
對的, 確實是明文, 不然服務端沒法肯定向客戶端推送哪張證書
並且, 也無法使用密文, 由於密鑰還沒有協商好
再者, 使用密文也沒有意義, 篡改域名只能影響服務端返回的證書, 而全部的證書原本就都是公開的
2014年2月 9日 11:41 | # | 引用
CJey 說:
@李狗蛋:
不太能理解你想表達的意思
不過, SSL/TLS協議並不關心雙方的IP, DNS劫持是沒法攻擊SSL/TLS的
因此, 我以爲你的這個測試結果另有緣由
2014年2月 9日 11:53 | # | 引用
onion 說:
其實,看阮兄的博客主要目的就是學習阮兄的總結與再表達能力,對於這篇來講,真的不懂,可是感受看得很舒服,層次清晰,用語準確,贊!
2014年2月10日 11:43 | # | 引用
masstensor 說:
文章寫的淺顯易懂,看了頗有收穫。不過,須要說明的是,使用PKI機制進行密鑰交換隻是TLS規範的一種實現形式,還有其餘的形式能夠用於密鑰交換,好比SRP和PSK協議。
2014年2月11日 10:19 | # | 引用
twd2 說:
若是有中間人經過判斷域名,來決定是否阻斷鏈接怎麼辦呢
2014年2月13日 00:30 | # | 引用
nuooo 說:
請考慮介紹下經常使用於SPDY的HTTPS falst start握手,它比標準的握手少一個「server finished"的步驟
2014年2月16日 03:13 | # | 引用
sunny 說:
好文章。
2014年2月23日 11:35 | # | 引用
點虎 說:
感謝!
沒有微信公衆號?
2014年2月24日 10:35 | # | 引用
hyh 說:
文中的 SeverHello 是否是應該是 ServerHello?
2014年2月27日 20:54 | # | 引用
GlacJAY 說:
只有第一次的握手過程是明文的,以後的自動重協商通訊是用上一次的密鑰來加密的。
2014年3月 1日 13:19 | # | 引用
yd 說:
您好,我有一個疑問。
第一步,服務器端的響應內容包含證實服務器自身的證書,客戶端獲得證書後進行有效性驗證,
請問客戶端是如何進行驗證的?根據哪些信息驗證的?
2014年3月11日 15:43 | # | 引用
dcb110 說:
查了好多文章,終於在這裏把整個握手流程以及中間一些疑問搞清楚了,如今再去看那些代碼,清楚了不少,感謝博主。
2014年3月13日 13:45 | # | 引用
Bravluna 說:
證書裏是服務器的公鑰和身份信息,這些是通過證書頒發機構即CA公證過的,客戶端拿到後去CA驗證,看這個公鑰是否是服務器的,若不是說明證書是僞造的,固然若是證書通過數字簽名證書就不可能被僞造了
2014年4月30日 23:29 | # | 引用
ZeroLing 說:
來支持一下阮老師寫的東西
2014年5月24日 16:47 | # | 引用
Charles 說:
看來講清楚這個東西,仍是太過難了一點,這個文章也太過概述了,感受不少關鍵點沒有說清楚啊,看得我好累。不過仍是感謝阮老師,已經讓我省了很多時間了。
2014年5月29日 23:12 | # | 引用
heliar 說:
這裏還有一個信任鏈的問題,通常都是有一家第三方的根證書籤名機構辦法證書,咱們相信這個第三方機構,從而相信它頒發的證書,固然也有根證書受權下一層的證書頒發機構,而後由這個機構給網站服務器作驗證的狀況
2014年7月19日 02:29 | # | 引用
Pingia 說:
我感受4。3部分 的(1)步和(2)(3)兩步中間還有些步驟能夠註明清楚點。
事實上服務端和客戶端在擁有pms後計算出來的密鑰並非會話密鑰,而是一箇中間密鑰,最終的會話密鑰是經過這個中間密鑰計算出來的。至於這個計算方法,我也不清楚是什麼?有知道的朋友望告知。
還有這一部分最後一句:
此外,若是前一步,服務器要求客戶端證書,客戶端會在這一步發送證書及相關信息。
我感受客戶端發送證書應該是在這一步驟以前。
2014年8月23日 13:31 | # | 引用
王正一 說:
通俗易懂,太讚了
2014年9月15日 14:26 | # | 引用
freenet 說:
講得很是好!學習了...
2014年10月 2日 16:58 | # | 引用
ikong 說:
2014年10月 9日 02:56 | # | 引用
興傑 說:
提問一下,
握手的第3步,pre-master key 若是被攔截,是否能夠被僞造或篡改?
由於只使用服務器的公鑰加密。
2014年10月14日 12:09 | # | 引用
feix 說:
關於 至於爲何必定要用三個隨機數,來生成"會話密鑰" 這個地方,其實還有一點:pre-master key 用服務器的公鑰加密,能夠防止第三方冒充服務器,由於任何人均可以獲取已經公開的服務器公鑰與客戶段進行通訊。想要得到 pre-master key 明文只有利用服務器的私鑰進行解密,因此這裏進行了服務器的身份驗證,也防止了中間人攻擊。
另外,當服務器須要驗證客戶端時,客戶端在發送 pre-master key 以前須要發送客戶端公鑰到服務器,能夠選擇對 pre-master key 用客戶端的私鑰簽名而後再用服務器公鑰加密,則服務器收到 pre-master key 同時對客戶端進行了身份驗證。
2014年10月16日 01:27 | # | 引用
中國證書CHINASSL 說:
好文章,通俗易懂的介紹SSL,本文將引用的中國證書CHINASSL博客,謝謝
2014年10月21日 10:38 | # | 引用
lp 說:
有個問題,握手時是明文通訊,那就會被截獲到公鑰、三個隨機數,這樣對話密鑰不久能夠知道了?那後面的對話加密不就會被解密?
2014年12月20日 01:41 | # | 引用
goodboy1983 說:
若是有個proxy, 先和客戶端創建鏈接(不下發服務器證書,也不要求客戶端上報證書),再和SP創建鏈接。 對服務器下發的證書默認接受。 至關於 CLIENT-PROXY之間是互相不認證證書,PROXY-WEB SERVER之間是驗證服務器證書。 是否有安全隱患?
2014年12月20日 03:02 | # | 引用
nowlater 說:
@goodboy1983: 應該不會有安全隱患吧,pre-master key是用服務器端公鑰加密的,client-proxy沒法解密,不能獲取到pre-master key。在安全要求更高的金融領域,服務器端會認證客戶端,好比銀行會給客戶發u盾。這就更安全了。
2014年12月26日 11:54 | # | 引用
哈哈 說:
服務器收到客戶端的第三個隨機數pre-master key以後,計算生成本次會話所用的"會話密鑰"。 這個會話密鑰怎麼計算的呢?
2015年1月13日 19:57 | # | 引用
youyingyang 說:
阮一峯同志是一座寶庫
4年以前就開始看您的博客,可是基本只看人文社科類和科普性質的,視野很開闊,寫的很棒。
最近隨着本身的興趣變化,開始學習編程,沒想到搜「RESTful架構」,第一篇文章就是您的,寫的太好了,明白如水!
高手有不少,可是樂意長時間堅持分享,並且作科普作的這麼好的高手太少了!
感謝!
2015年1月15日 15:43 | # | 引用
hilojack 說:
將域名加密仍是有意義的,好比GFW 或者 Hacker 等想知道你請求了哪些網站,醬紫
2015年3月23日 23:57 | # | 引用
hilojack 說:
關於TLS/SSL 四次握手的一個疑問。
在協商會話密鑰的階段:
客戶端的請求是用服務端的公鑰加密的,第三方截獲後是沒有辦法解密的;
服務端返回的請求是用服務端的私鑰加密的,第三方截獲後能夠經過公鑰解密的。
這引起個人疑問,在最後第4步,服務端返回的會話密鑰(Session Key) 是用服務端的私鑰加密的,那第三方不就能夠解密出這個Session Key 嗎?有了這個Session Key 後不就能夠破譯出通訊數據嗎?
2015年3月24日 12:01 | # | 引用
Zhaodawei 說:
第四步服務器不會返回會話密鑰!!!會話密鑰是客戶端和服務端各自經過三個隨機數和一個密鑰導出器最終導出的
2015年4月22日 16:06 | # | 引用
zhaodawei 說:
文中說「三個隨機數經過一個密鑰導出器最終導出一個對稱密鑰」,密鑰導出器是什麼?服務的公鑰嗎?
2015年4月22日 16:54 | # | 引用
zhaodawei 說:
2015年4月22日 19:23 | # | 引用
shun.aaron 說:
請教一個問題:
若是網絡中有一臺設備,這個設備具備了https服務器的證書和私鑰,是否是意味着:這個設備可以經過服務器的私鑰來計算出第三個隨機數,而後根據相關算法來計算出服務器和client之間的通訊祕鑰?
這樣就表明了服務器和client之間的通訊內容不在是私密性的了?
2015年5月 9日 13:58 | # | 引用
passerbywhu 說:
HTTPS服務器的私鑰你都有了還想怎樣。。。-_-
2015年6月25日 11:36 | # | 引用
danieldong 說:
若是key exchange算法是ECDH,那麼就不是索要公鑰了,也就是說,不採用非對稱加密來產生master-key
2015年7月 8日 17:18 | # | 引用
撒啊 說:
請教一下,爲何在session ticket生效的狀況下,依然須要交互隨機數? session ticket生效有,已經不用從新生成對稱密鑰了。
2015年7月21日 23:40 | # | 引用
jedihy 說:
阮老師這篇博客說的很差。先後都有矛盾,有些地方不明確,容易誤導。
若是認定握手是徹底明文,按阮老師的說法,那中間人直接就能夠攻擊了,由於他知道全部信息。關鍵在於隨機數的傳遞這裏,會不會用Server的公鑰加密。這一點沒有強調的話,這篇博客有什麼意義,通訊安全性的關鍵在這裏。正是用了中間人解不出的信息(須要私鑰),因此安全才獲得的保障,而並非由於你用了多少個隨機數。不加密的話,你來回發一萬次隨機數中間人也可以看到。後面的對稱密鑰通訊過程就是扯淡了。
2015年7月27日 09:46 | # | 引用
大山 說:
我的以爲隨機數應該最後是這樣的結果:3個隨機數以某種組合並結合加密算法,客戶端和服務器端各自都算出來了動態的私鑰和公鑰了,這個時候的通訊再也不是以服務器最先的公鑰和私鑰爲準,而是在兩方都知道公鑰私鑰的狀況下通訊,服務器端以私鑰加密,客戶端以公鑰解密,客戶端以公鑰加密,服務器端以私鑰解密,至於服務器最原始的公鑰和私鑰,就是爲了保證隨機數的安全,不知道這樣對不對
2015年8月28日 00:57 | # | 引用
少時誦詩書 說:
不對,握手完成後就是對稱加密,怎麼還會有公鑰私鑰這種非對稱加密方法
2015年8月31日 13:06 | # | 引用
小白 說:
大體是看明白了,誰能提供一個pcap包 詳細分析下就更加好了。我本身抓了包,都是加密的,看不明白呢
2015年9月 8日 16:30 | # | 引用
YorkYang 說:
一個證書可不能夠供兩個(不一樣IP)服務器使用? 文中講的 "真實IP" 的校驗依據是否爲發包的IP?
2015年12月14日 12:01 | # | 引用
gaodi 說:
求助各位大神,如今已知Server端私鑰,用wireshark截取握手階段client和server的random和加密了的pre_master_secret,如何具體解析出https中,http報文內容,最好能有C語言實現的函數和代碼,多謝。
2016年1月15日 16:24 | # | 引用
王鬆 說:
贊,忽然發現,寫技術博客,排版很重要!
2016年1月16日 16:21 | # | 引用
Pingia 說:
是這樣的,我也想這麼一問。
2016年2月21日 12:48 | # | 引用
Pingia 說:
後面的步驟須要解密這個key,若是被篡改,將不能解密,以後的步驟都不能繼續下去了,而後就沒有而後了。
2016年2月21日 12:55 | # | 引用
Pingia 說:
2016年2月21日 13:03 | # | 引用
Pingia 說:
我的以爲這個 不在ssl協議要解決的範疇以內。
2016年2月21日 13:07 | # | 引用
Pingia 說:
說錯了,第三個也傳輸給客戶端的,只是第一個隨機數須要私鑰解開,這能夠進行防範。
2016年2月21日 13:26 | # | 引用
Pingia 說:
2016年2月21日 13:30 | # | 引用
Pingia 說:
2016年2月21日 13:46 | # | 引用
bencanber 說:
解密只能使用服務器的私鑰解密,而證書中只包含服務器的公鑰,因此不會被破解
2016年2月22日 15:07 | # | 引用
pengfei 說:
我有個疑問,好比我控制着代理服務器
我知道 協商協議版本都是1.0 我也知道三次隨機數第一次客戶給服務器的 10,第二次服務器給客戶端的 1050 第三次客戶端給服務器的119,而後還知道他們協商的加密算法 RSA. 那我就能夠本身按照加密算法RSA,用我看到的三個隨機數生成一個祕鑰了,這樣我不是仍是能夠解開你的通訊內容嗎?
2016年3月 3日 12:01 | # | 引用
andy_chen 說:
"握手階段"的全部通訊都是明文的。
對於這個,不知個人理解能否正確?
1.客戶端->服務器:隨機數,支持的加密方法
2.服務器->客戶端:隨機數,肯定加密方法
3.客戶端->服務器:隨機數(公鑰加密)
這樣,第一第二的隨機數雖然可能被其餘人截取,可是因爲第三個隨機數是經過公鑰加密的,因此,只有對應的私鑰能夠解密,是安全的。
因此經過這三個隨機數以及第二步肯定的對稱加密的方法,客戶端以及服務端各自生成對話密鑰。以後就經過這個對話密鑰來進行通訊
2016年3月 3日 14:39 | # | 引用