客戶端在驗(yàn)證證書時(shí),是個(gè)復(fù)雜的過程,會(huì)走證書鏈逐級驗(yàn)證,驗(yàn)證的過程不僅需要「用 CA 公鑰解密證書」以及「用簽名算法驗(yàn)證證書的完整性」,而且為了知道證書是否被 CA 吊銷,客戶端有時(shí)還會(huì)再去訪問 CA, 下載 CRL 或者 OCSP 數(shù)據(jù),以此確認(rèn)證書的有效性。這個(gè)訪問過程是 HTTP 訪問,因此又會(huì)產(chǎn)生一系列網(wǎng)絡(luò)通信的開銷,如 DNS 查詢、建立連接、收發(fā)數(shù)據(jù)等。
CRL
CRL 稱為證書吊銷列表(Certificate Revocation List),這個(gè)列表是由 CA 定期更新,列表內(nèi)容都是被撤銷信任的證書序號,如果服務(wù)器的證書在此列表,就認(rèn)為證書已經(jīng)失效,不在的話,則認(rèn)為證書是有效的。但是 CRL 存在兩個(gè)問題:
第一個(gè)問題,由于 CRL 列表是由 CA 維護(hù)的,定期更新,如果一個(gè)證書剛被吊銷后,客戶端在更新 CRL 之前還是會(huì)信任這個(gè)證書,實(shí)時(shí)性較差;
因此,現(xiàn)在基本都是使用 OCSP ,名為在線證書狀態(tài)協(xié)議(Online Certificate Status Protocol)來查詢證書的有效性,它的工作方式是向 CA 發(fā)送查詢請求,讓 CA 返回證書的有效狀態(tài)。不必像 CRL 方式客戶端需要下載大大的列表,還要從列表查詢,同時(shí)因?yàn)榭梢詫?shí)時(shí)查詢每一張證書的有效性,解決了 CRL 的實(shí)時(shí)性問題。OCSP 需要向 CA 查詢,因此也是要發(fā)生網(wǎng)絡(luò)請求,而且還得看 CA 服務(wù)器的“臉色”,如果網(wǎng)絡(luò)狀態(tài)不好,或者 CA 服務(wù)器繁忙,也會(huì)導(dǎo)致客戶端在校驗(yàn)證書這一環(huán)節(jié)的延時(shí)變大。
OCSP Stapling
于是為了解決這一個(gè)網(wǎng)絡(luò)開銷,就出現(xiàn)了 OCSP Stapling,其原理是:服務(wù)器向 CA 周期性地查詢證書狀態(tài),獲得一個(gè)帶有時(shí)間戳和簽名的響應(yīng)結(jié)果并緩存它。當(dāng)有客戶端發(fā)起連接請求時(shí),服務(wù)器會(huì)把這個(gè)「響應(yīng)結(jié)果」在 TLS 握手過程中發(fā)給客戶端。由于有簽名的存在,服務(wù)器無法篡改,因此客戶端就能得知證書是否已被吊銷了,這樣客戶端就不需要再去查詢。
Session ID 的工作原理是,客戶端和服務(wù)器首次 TLS 握手連接后,雙方會(huì)在內(nèi)存緩存會(huì)話密鑰,并用唯一的 Session ID 來標(biāo)識,Session ID 和會(huì)話密鑰相當(dāng)于 key-value 的關(guān)系。當(dāng)客戶端再次連接時(shí),hello 消息里會(huì)帶上 Session ID,服務(wù)器收到后就會(huì)從內(nèi)存找,如果找到就直接用該會(huì)話密鑰恢復(fù)會(huì)話狀態(tài),跳過其余的過程,只用一個(gè)消息往返就可以建立安全通信。當(dāng)然為了安全性,內(nèi)存中的會(huì)話密鑰會(huì)定期失效。但是它有兩個(gè)缺點(diǎn):
為了解決 Session ID 的問題,就出現(xiàn)了 Session Ticket,服務(wù)器不再緩存每個(gè)客戶端的會(huì)話密鑰,而是把緩存的工作交給了客戶端,類似于 HTTP 的 Cookie。客戶端與服務(wù)器首次建立連接時(shí),服務(wù)器會(huì)加密「會(huì)話密鑰」作為 Ticket 發(fā)給客戶端,交給客戶端緩存該 Ticket。客戶端再次連接服務(wù)器時(shí),客戶端會(huì)發(fā)送 Ticket,服務(wù)器解密后就可以獲取上一次的會(huì)話密鑰,然后驗(yàn)證有效期,如果沒問題,就可以恢復(fù)會(huì)話了,開始加密通信。對于集群服務(wù)器的話,要確保每臺服務(wù)器加密 「會(huì)話密鑰」的密鑰是一致的,這樣客戶端攜帶 Ticket 訪問任意一臺服務(wù)器時(shí),都能恢復(fù)會(huì)話。Session ID 和 Session Ticket 都不具備前向安全性,因?yàn)橐坏┘用堋笗?huì)話密鑰」的密鑰被破解或者服務(wù)器泄漏「會(huì)話密鑰」,前面劫持的通信密文都會(huì)被破解。同時(shí)應(yīng)對重放攻擊也很困難,這里簡單介紹下重放攻擊工作的原理。假設(shè) Alice 想向 Bob 證明自己的身份。Bob 要求 Alice 的密碼作為身份證明,愛麗絲應(yīng)盡全力提供(可能是在經(jīng)過如哈希函數(shù)的轉(zhuǎn)換之后)。與此同時(shí),Eve 竊聽了對話并保留了密碼(或哈希)。交換結(jié)束后,Eve(冒充 Alice )連接到 Bob。當(dāng)被要求提供身份證明時(shí),Eve 發(fā)送從 Bob 接受的最后一個(gè)會(huì)話中讀取的 Alice 的密碼(或哈希),從而授予 Eve 訪問權(quán)限。重放攻擊的危險(xiǎn)之處在于,如果中間人截獲了某個(gè)客戶端的 Session ID 或 Session Ticket 以及 POST 報(bào)文,而一般 POST 請求會(huì)改變數(shù)據(jù)庫的數(shù)據(jù),中間人就可以利用此截獲的報(bào)文,不斷向服務(wù)器發(fā)送該報(bào)文,這樣就會(huì)導(dǎo)致數(shù)據(jù)庫的數(shù)據(jù)被中間人改變了,而客戶是不知情的。避免重放攻擊的方式就是需要對會(huì)話密鑰設(shè)定一個(gè)合理的過期時(shí)間。