1、前言算法
隨着安全的普及,https通訊應用愈加普遍,可是因爲對https不熟悉致使開發人員頻繁錯誤的使用https,例如最多見的是未校驗https證書從而致使「中間人攻擊」,而且因爲修復方案也一直是個坑,致使修復這個問題時踩各類坑,故謹以此文簡單的介紹相關問題。瀏覽器
本文第一節主要講述https的握手過程,第二節主要講述常見的「https中間人攻擊」場景,第三節主要介紹證書校驗修復方案,各位看官可根據本身口味瀏覽。安全
2、HTTPS握手過程服務器
首先來看下https的工做原理,上圖大體介紹了https的握手流程,後續咱們經過抓包看下每一個握手包到底幹了些什麼神奇的事。session
注:本文全部內容以TLS_RSA_WITH_AES_128_CBC_SHA加密組件做爲基礎進行說明,其餘加密組件以及TLS版本會存在必定差別,例如TLS1.3針對移動客戶端有了很大的改動,如今的ECDHE等密鑰交換算法與RSA做爲密鑰交換算法也徹底不同,因此有些地方和你們實際操做會存在必定出入。dom
1.TCP三次握手性能
我訪問的支付寶的官網www.alipay.com抓取的數據。優化
2.Client Helloui
TLS的版本號和隨機數random_c:這個是用來生成最後加密密鑰的因子之一,它包含兩部分,時間戳和隨機數 session-id:用來標識會話,第一次握手時爲空,若是之前創建過,能夠直接帶過去從而避免徹底握手 Cipher Suites加密組件列表:瀏覽器所支持的加密算法的清單客戶端支持的加密簽名算法的列表,讓服務器進行選擇 擴展字段:好比密碼交換算法的參數、請求主機的名字,用於單ip多域名的狀況指定域名。加密
3.Sever Hello
隨機數rando_s,這個是用來生成最後加密密鑰的因子之一,包含兩部分,時間戳和隨機數 32字節的SID,在咱們想要從新鏈接到該站點的時候能夠避免一整套握手過程。 在客戶端提供的加密組件中,服務器選擇了TLS_RSA_WITH_AES_128_CBC_SHA組件。
4.Certificate
證書是https裏很是重要的主體,可用來識別對方是否可信,以及用其公鑰作密鑰交換。能夠看見證書裏面包含證書的頒發者,證書的使用者,證書的公鑰,頒發者的簽名等信息。其中Issuer Name是簽發此證書的CA名稱,用來指定簽發證書的CA的可識別的惟一名稱(DN, Distinguished Name),用於證書鏈的認證,這樣經過各級實體證書的驗證,逐漸上溯到鏈的終止點,便可信任的根CA,若是到達終點在本身的信任列表內未發現可信任的CA則認爲此證書不可信。
驗證證書鏈的時候,用上一級的公鑰對證書裏的簽名進行解密,還原對應的摘要值,再使用證書信息計算證書的摘要值,最後經過對比兩個摘要值是否相等,若是不相等則認爲該證書不可信,若是相等則認爲該級證書鏈正確,以此類推對整個證書鏈進行校驗。
二級機構的證書。
支付寶官網簽名證書。
不只僅進行證書鏈的校驗,此時還會進行另外一個協議即Online Certificate Status Protocol, 該協議爲證書狀態在線查詢協議,一個實時查詢證書是否吊銷的方式,客戶端發送證書的信息並請求查詢,服務器返回正常、吊銷或未知中的任何一個狀態,這個查詢地址會附在證書中供客戶端使用。
5.Server Hello Done
這是一個零字節信息,用於告訴客戶端整個server hello過程已經結束。
6.ClientKeyExchange
客戶端在驗證證書有效以後發送ClientKeyExchange消息,ClientKeyExchange消息中,會設置48字節的premaster secret(由於的TLS版本的緣由,這裏沒有顯示premaster),經過密鑰交換算法加密發送premaster secret的值,例如經過 RSA公鑰加密premaster secret的獲得Encrypted PreMaster傳給服務端。PreMaster前兩個字節是TLS的版本號,該版本號字段是用來防止版本回退攻擊的。
從握手包到目前爲止,已經出現了三個隨機數(客戶端的random_c,服務端的random_s,premaster secret),使用這三個隨機數以及必定的算法便可得到對稱加密AES的加密主密鑰Master-key,主密鑰的生成很是的精妙。
7.Change Cipher Spec
發送一個不加密的信息,瀏覽器使用該信息通知服務器後續的通訊都採用協商的通訊密鑰和加密算法進行加密通訊。
8.Encrypted Handshake Message
驗證加密算法的有效性,結合以前全部通訊參數的 hash 值與其它相關信息生成一段數據,採用協商密鑰 session secret 與算法進行加密,而後發送給服務器用於數據與握手驗證,經過驗證說明加密算法有效。
9.Change_cipher_spec
Encrypted Handshake Message經過驗證以後,服務器一樣發送 change_cipher_spec 以通知客戶端後續的通訊都採用協商的密鑰與算法進行加密通訊。
10.Encrypted Handshake Message
一樣的,服務端也會發送一個Encrypted Handshake Message供客戶端驗證加密算法有效性。
11.Application Data
通過一大串的的計算以後,終於一切就緒,後續傳輸的數據可經過主密鑰master key進行加密傳輸,加密數據查看圖中的Encrypted Apploication Data字段數據,至此https的一次完整握手以及數據加密傳輸終於完成。
https裏還有不少可優化而且不少精妙的設計,例如爲了防止常常進行完整的https握手影響性能,因而經過sessionid來避免同一個客戶端重複完成握手,可是又因爲sessionid消耗的內存性能比較大,因而又出現了new session ticket,若是客戶端代表它支持Session Ticket而且服務端也支持,那麼在TLS握手的最後一步服務器將包含一個「New Session Ticket」信息,其中包含了一個加密通訊所須要的信息,這些數據採用一個只有服務器知道的密鑰進行加密。這個Session Ticket由客戶端進行存儲,並能夠在隨後的一次會話中添加到 ClientHello消息的SessionTicket擴展中。雖然全部的會話信息都只存儲在客戶端上,可是因爲密鑰只有服務器知道,因此Session Ticket仍然是安全的,所以這不只避免了性能消耗還保證了會話的安全性。
最後咱們可使用openssl命令來直觀的看下https握手的流程: