Https 詳解

chendong發表於2018-02-06

Https 詳解

超文字傳輸安全協議(HTTPS,常稱為 HTTP over TLS/SSL)是一種通過計算機網路進行安全通訊的傳輸協議。HTTPS 經由 HTTP 進行通訊,但利用 SSL/TLS 來加密資料包。HTTPS 開發的主要目的,是提供對網站伺服器的身份認證,保護交換資料的隱私與完整性。

本文主要介紹 :

  • Https 如何保證資料傳輸的安全
  • CA 的存在及其安全性
  • 證照工具 keytool
  • 證照驗證流程
  • Https 握手流程
  • Android 下進行 Https訪問

TLS/SSL

TCP (Transmission Control Protoco) 傳輸層控制協議

TLS (Transport Layer Security) 傳輸層安全協定

SSL (Secure Socket Layer) 安全套接層

HTTP(Hypertext Transfer Protocol) 基於 TCP 協議,無連線,每次連線只處理一個請求,結束後斷開連線;無狀態,無法保持使用者狀態,使用 cookiesession 解決。

HTTPS(HTTP over TLS/SSL) 安全的 http 協議,HTTP 協議和 TCP 協議之間增加了 TLS/SSL 保證資料的安全傳輸。

歷史程式:

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.1,TLS 1.1為SSL 3.2,TLS 1.2為SSL 3.3。

目前,應用最廣泛的是TLS 1.0,接下來是SSL 3.0。但是,主流瀏覽器都已經實現了TLS 1.2的支援。
複製程式碼

Https 安全性

HTTP 協議的不安全性體現在 3 個方面:

風險 描述 https解決方案
竊聽風險 攻擊者可以獲知訊息內容 訊息加密
篡改風險 攻擊者可以篡改訊息內容 訊息摘要
冒充風險 攻擊者可以冒充其他人蔘與通訊 CA 身份認證
CA 不可信 信任的 CA 亂簽發證照 證照鎖

竊聽/嗅探

指的是路由上的攻擊者,可以偷窺到傳輸的訊息內容。

解決方案:

  1. 使用對稱加密演算法加密通訊內容,竊聽者獲取到訊息也無法識別,存在問題 -> 金鑰傳遞的安全性,在網路上面的通訊雙方都是陌生人,無法識別身份,金鑰要通過網路傳輸時很有可能被竊取。❌

  2. 使用非對稱加密演算法加密通訊內容,釋出的公鑰用來加密,私鑰用來解密,即使公鑰被竊取,依然無法解密訊息內容。存在問題 -> 速度慢,消耗大;公鑰被公開,如果回發私鑰加密的資訊,任何持有公鑰的人都可以解密。❌

  3. 最終,訊息內容仍舊使用對稱加密演算法來加密,但是前期對稱加密的金鑰交換使用非對稱加密來進行,客戶端使用服務端公鑰加密對稱加密的金鑰,這樣就只有擁有私鑰的服務端可以獲取到加密內容,由於對稱加密金鑰長度有限,加密的時間可以忽略不計。✅

以上,可以防止嗅探的問題,路由上面的攻擊者即使獲取到訊息也無法識別訊息的內容。

訊息篡改

訊息加密以後攻擊者無法獲取訊息內容的含義,但是可以篡改訊息內容,篡改之後接收方也無法感知。

解決方案:

  • 採用 訊息摘要(見文末註腳) 演算法可以驗證資料的完整性,我們將傳送的訊息進行摘要,連同訊息一起傳送給接收方,接收方拿到訊息之後對訊息做同樣的摘要處理,對比摘要結果,即可知道訊息有沒有被篡改。

以上,可以解決訊息完整性和真實性的問題。

中間人攻擊

中間人攻擊Man-in-the-middle Attack,MITM)指的是攻擊者在鏈路上偽裝自己,與通訊雙方分別建立聯絡,並交換其所收到的資料,使通訊的兩端認為他們正在通過一個私密的連線與對方直接對話,但事實上整個會話都被攻擊者完全控制。

作為 AB 通訊路由上的攻擊者 M,作為中間人偽造自己的身份。A 向 B 請求用於通訊的 PK_A,但是被中間人 M 截獲,他偽造生成了假的公鑰 PK_M,傳送給了 A,同時向 B 請求並獲取了 B 的公開金鑰 PK_B,原來安全的通訊過程 A(使用 PK_B 加密) -> 安全 -> B(使用 SK_B 解密),現在變成了 A(使用 PK_M 加密) -> M(使用 SK_M 解密獲取明文內容,再用 PK_B 加密,可能篡改資料) -> B(使用 SK_B 解密)

出現問題的原因在於,金鑰在交換的初期是不安全的,網路上的通訊雙方,無法確定對方的身份,即無法獲悉當前的公鑰是不是自己想要的公鑰。

解決方案:

  • 引入第三方公正作信用背書,第三方公正具有權威性,他和通訊雙方沒有關係,接收方無條件信任公證機構,也就會信任他簽名的資訊。這種機構被稱為 CA(Certificate Authority 機構,即數字證照認證機構。CA 機構與瀏覽器和作業系統廠商合作,將公鑰內建在瀏覽器和作業系統中,也就是不走網路傳輸了,這樣一定程度上保證了公鑰不會被竊取篡改。

  • 服務端 Server 將自己的訊息(訊息內容大致包括電子簽證機關的資訊、公鑰使用者資訊、公鑰、權威機構的簽字和有效期等)進行摘要之後,發給 CA 機構 AUTH 簽發證照,Server 使用自己的私鑰對訊息摘要加密,形成證照,並將證照和訊息內容傳送給 ClientClient 收到後,發現是 AUTH 的證照,同時對 AUTH 是信任的,則會使用 AUTH 的公鑰對證照進行解密(這裡涉及證照鏈的驗證,其實要更加複雜),獲取到訊息摘要,同時對收到的訊息進行摘要,對比,如果一致則說明內容沒有被篡改,是可信的,因為生成加密資料的私鑰只有 CA 機構才有,這一過程稱為驗證數字簽名。

以上,可以解決中間人攻擊的文圖,另外涉及到非對稱加密的兩種應用場景,詳細介紹見文末非對稱加密應用場景

CA 錯誤簽發

受信任的 CA(證照頒發機構)有好幾百個,他們成為整個網站身份認證過程中一個較大的攻擊面。實際上,目前由於 CA 失誤導致錯誤簽發證照,以及個別 CA 出於某些目的(如監控加密流量)故意向第三方隨意簽發證照這兩種情況時有發生。現有的證照信任鏈機制最大的問題是,任何一家受信任的 CA 都可以簽發任意網站的站點證照,這些證照在客戶端看來,都是合法的,是可以通過驗證的。

解決方案:

  • 證照鎖(Certificate Pinning),證照鎖是為了防範由 「偽造或不正當手段獲得網站證照」 造成的中間人攻擊。

  • 證照鎖類似於 HPKP 技術(下面有簡單介紹),給予我們主動選擇信任 CA 的權利。它的工作原理就是使用預先設定的證照指紋和伺服器傳過來的證照鏈中的證照指紋進行匹配,只要有任何一對指紋匹配成功,則認為是一次合法的連線,否則禁止本次連結。

  • 也就是說,使用證照鎖之後,不是所有被系統信任的 CA 都可以通過驗證,只有我儲存了指紋的一些 CA 簽發的證照才可以,比如有 100 個 CA 機構,但我就信任其中一個,我可以保證這個 CA 不會亂簽發證照,那我就只儲存這個 CA 的指紋,即使攻擊者從其他的 99 個 CA 簽發證照,對我進行攻擊,也無法完成連線。

  • 證照鎖定增加了安全性,但限制了你的伺服器團隊升級 TLS 證照的能力。

以上,可以解決 CA 機構簽發證照權威性不足的問題,相關解決方案詳見文末 簽發證照權威性問題

? 綜上,對稱加密通訊 + 非對稱加密交換金鑰 + CA 認證身份 + 證照鎖鎖定證照指紋 共同保證了 https 的安全性。

CA 安全性

作為全網 https 連線的權威公正,CA 的安全性至關重要。

安全儲存 CA

從根 CA 開始到直接給客戶發放證照的各層次 CA,都有其自身的金鑰對。CA 中心的金鑰對一般由硬體加密伺服器在機器內直接產生,並儲存於加密硬體內,或以一定的加密形式存放於金鑰資料庫內。加密備份於 IC 卡或其他儲存介質中,並以高等級的物理安全措施保護起來。

金鑰的銷燬要以安全的金鑰衝寫標準,徹底清除原有的金鑰痕跡。需要強調的是,根 CA 金鑰的安全性至關重要,它的洩露意味著整個公鑰信任體系的崩潰,所以 CA 的金鑰保護必須按照最高安全級的保護方式來進行設定和管理。CA 的私鑰是自己靠上述方法保管的,不對外公開。

所以 CA 金鑰的安全性依賴於物理硬體的安全性,不通過網路傳輸避免了被攻擊的可能。

CA 的公鑰是廠商跟瀏覽器和作業系統合作,把公鑰預設裝到瀏覽器或者作業系統環境裡。比如 firefox 就自己維護了一個可信任的 CA 列表,而 chromeIE 使用的是作業系統的 CA 列表。

證照鏈

現在大的 CA 都會有證照鏈,證照鏈的好處一是安全,保持根 CA 的私鑰離線使用。第二個好處是方便部署和撤銷,即如果證照出現問題,只需要撤銷相應級別的證照,根證照依然安全。

CA 證照都是自簽名,即用自己的公鑰和私鑰完成了簽名的製作和驗證。而證照鏈上的證照籤名都是使用上一級證照的金鑰對完成簽名和驗證的。

證照驗證

證照是否是信任的有效證照

  1. 是否信任 :接收方內建了信任根證照的公鑰,需要證照是不是這些信任根證照籤發的或者信任根證照的二級證照機構頒發的。

  2. 是否有效:證照是否在有效期內。

  3. 是否合法:對方是不是上述證照的合法持有者,證明對方是否持有證照的對應私鑰。驗證方法兩種,一種是對方籤個名,我用證照驗證簽名;另外一種是用證照做個信封,看對方是否能解開。

  4. 是否吊銷:驗證是否吊銷可以採用黑名單方式或者 OCSP 方式。黑名單就是定期從 CA 下載一個名單列表,裡面有吊銷的證照序列號,自己在本地比對一下就行。優點是效率高。缺點是不實時。OCSP 是實時連線 CA 去驗證,優點是實時,缺點是效率不高。

自簽名證照如何驗證

自簽名證照是自己給自己簽發的證照,也就是說自己做自己的 CA 機構,為自己擔保,因此無法內建在系統當中,因此我們通常會在客戶內建一個證照檔案,自己進行校驗。

簡單來說,握手流程需要兩對金鑰對:

  1. 一對 CA 的金鑰對 JKS_A,由 CA 機構維護,通常他的公鑰內建在 os 中,用來簽名服務端資訊摘要,保證服務端公鑰的真實性,避免中間人攻擊。
  2. 一對伺服器的金鑰對 JKS_B,他是握手過程中隨機生成的,然後用「它的公鑰及其他內容」的摘要去向 CA 實時簽發證照,用來進行對稱金鑰的加密傳輸。

自簽名證照就是不走 CA 機構,而是自己生成一對金鑰對 JKS_C,他的作用就好比 CA 的金鑰對 JKS_A,也是為了保證公鑰的真實性,握手過程和原來一樣,只是我們不需要去 CA 簽發證照了,用自己的 JKS_C 簽發就可以了;同樣因為 JKS_C 是我們自己的金鑰對,公鑰沒有被內建在 os 中,所以此時需要我們自己把 cert 檔案(JKS_C 的公鑰)放到本地,自己完成原本由 os 完成的 CA 校驗任務。

雙向驗證

雙向驗證指的是,不光客戶端要驗證來自伺服器的連線是不是可靠,伺服器也要驗證客戶端。

服務端也會內建一套受信任的 CA 證照列表,用於驗證客戶端證照的真實性。驗證過程和客戶端驗證服務端類似。

Https 握手

單向驗證握手過程:

  • 1、Client Hello ➡️

客戶端向伺服器傳送握手資訊,告知自己支援的加密演算法、摘要演算法、安全層協議版本、隨機數 Random-Secret-C

  • 2、Server Hello ⬅️

服務端隨機生成本次握手需要的非對稱加密的金鑰對(私鑰+公鑰),將來用來傳輸對稱加密金鑰。

服務端生成訊息,內容包含隨機數 Random-Secret-S,確定的一組加密演算法和摘要演算法,服務端公鑰,域名資訊等。

服務端對資訊內容摘要,使用摘要的資訊向 CA 機構申請的簽名證照。

服務端向客戶端傳送訊息和申請的證照。

如果需要雙向驗證的話,請求客戶端證照。

  • 3、驗證服務端證照,提取服務端公鑰 ➡️

客戶端從信任證照列表中發現是受信任的證照,會首先驗證證照是否被信任、有效性、合法性等資訊,驗證過程參照上面的 證照驗證

驗證通過,客戶端使用 CA 機構的公鑰對證照解密,拿到訊息的摘要,對真正的訊息內容進行摘要,對比確定訊息沒有被篡改,則取出服務端公鑰。

如果需要雙向驗證的話,向服務端傳送自己的證照。

客戶端生成隨機數字 Pre-Master-Secret,將其進行摘要處理,使用服務端公鑰對訊息和摘要結果加密,傳送給伺服器,併傳送一個編碼改變通知,說明以後將會開始加密通訊。

  • 4、生成對稱加密金鑰 ⬅️

如果需要雙向驗證的話,首先驗證客戶端證照,驗證過程類似客戶端驗證,驗證失敗則斷開連線

伺服器使用私鑰對收到的資訊解密,對訊息進行摘要對比無誤,則說明對稱加密的金鑰沒有被篡改,然後使用 Random-Secret-C,Random-Secret-S,Pre-Master-Secret 生成最終將要進行對稱加密通訊的金鑰 Master-Secret

伺服器使用 Master-Secret 加密一段握手資訊及其摘要,傳送給客戶端,併傳送一個編碼改變通知,說明以後將會開始加密通訊。

  • 5、客戶端驗證加密結果,握手結束 ?

客戶端使用 Random-Secret-C,Random-Secret-S,Pre-Master-Secret 生成同樣的對稱加密金鑰 Master-Secret,使用金鑰解密,並驗證資訊摘要,沒有問題則握手結束。

後面的通訊將會使用新生成的對稱加密金鑰加密進行。

圖解:

https

問題記錄

Q:為什麼要有 3 個隨機數?

不管是客戶端還是伺服器,都需要隨機數,這樣生成的金鑰才不會每次都一樣。由於 SSL 協議中證照是靜態的,因此十分有必要引入一種隨機因素來保證協商出來的金鑰的隨機性。對於RSA金鑰交換演算法來說,Pre-Master-Secret 本身就是一個隨機數,再加上 hello 訊息中的隨機,三個隨機數通過一個金鑰匯出器最終匯出一個對稱金鑰。

Pre-Master 的存在在於 SSL 協議不信任每個主機都能產生完全隨機的隨機數,如果隨機數不隨機,那麼 Pre-Master-Secret 就有可能被猜出來,那麼僅適用 Pre-Master-Secret 作為金鑰就不合適了,因此必須引入新的隨機因素,那麼客戶端和伺服器加上 Pre-Master-Secret 三個隨機數一同生成的金鑰就不容易被猜出了,一個偽隨機可能完全不隨機,可是是三個偽隨機就十分接近隨機了,每增加一個自由度,隨機性增加的可不是一。"

Q:放在 Android 客戶端的 cert 檔案是啥?

是自簽名證照的公鑰,自簽名證照就是自己做自己的 CA 機構,服務端會自己維護一個金鑰對 JKS,他就相當於 CA 的簽發證照的金鑰對,在握手過程中伺服器不需要走 CA 申請簽名證照了,自己簽發就可以,原本 CA 的公鑰被內建在 os 中,CA 的驗證不需要我們來關注,但是現在是自簽名的,自己做自己的 CA,所以 JKS 的公鑰我們要內建在客戶端中,自己完成驗證過程,替代原來 os 的驗證。

證照工具-keytool

提取證照內容為一個字串

keytool -printcert -rfc -file [srca.cer]
複製程式碼

生成金鑰對

keytool -genkey -alias [march_server] -keyalg RSA -keystore [march_server.jks] -validity 3600 -storepass [123456]
複製程式碼

讀取金鑰對資訊

keytool -list -v -keystore [srca.jks] -storepass [123456] 
複製程式碼

提取公鑰,簽發 cert 檔案

keytool -export -alias march_server -file march_server.cer -keystore march_server.jks -storepass 123456
複製程式碼

將客戶端公鑰匯入客戶端金鑰對中,主要是伺服器不能使用 cert 證照,需要匯入到 jks 檔案中

keytool -import -alias [march_client] -file [march_client.cer] -keystore [march_client_for_server.jks]
複製程式碼

搭建 https 服務

這部分內容參考了 CSDN-hongyang-Android Https 完全解析,這裡做一個彙總和整理。

藉助 tomcat 搭建簡單的 https 服務,主要是用來測試,之前使用 12306 的證照測試,但是前段時間 12306 證照換掉了,現在已經是正式證照了,所以不得以需要自己搭建一個簡單的服務來做訪問測試。

  • 搭建單向驗證的 https 服務

首先我們準備好金鑰和證照,使用 keytool 工具生成服務端 march_server.jks 金鑰對,然後提取服務端公鑰 march_server.cert

配置服務,主要是配置 tomcat/conf/server.xml 檔案,新增一個如下的 Connector

<!-- 
  https 測試服務
  clientAuth 和 truststoreFile 配置伺服器驗證客戶端
  keystoreFile 和 keystorePass 配置客戶端驗證伺服器
  -->
  <Connector
    
    clientAuth="false"
    
    keystoreFile="/Users/march/Documents/march_server.jks" 
    keystorePass="123456" 

    disableUploadTimeout="true" 
    enableLookups="true" 
    SSLEnabled="true" 
    acceptCount="100"  
    maxSpareThreads="75" 
    maxThreads="200" 
    minSpareThreads="5" 
    protocol="org.apache.coyote.http11.Http11NioProtocol" 
    scheme="https" 
    secure="true" 
    port="8443" 
    sslProtocol="TLS"/>
複製程式碼
  • 搭建雙向驗證的 https 服務

再生成客戶端金鑰對 march_client.jks,然後簽發客戶端公鑰 march_client.cert,為了能在服務端使用,將 march_client.cert 匯入到新的金鑰對 march_client_for_server.jks。使用的命令都可以在上一節找到,生成這幾個金鑰,是為了搭建後面的服務作準備。

更改 conf/server.xml 配置

<!-- 
  https 測試服務
  clientAuth 和 truststoreFile 配置伺服器驗證客戶端
  keystoreFile 和 keystorePass 配置客戶端驗證伺服器
   -->
  <Connector 
    
    clientAuth="true"
    truststoreFile="/Users/march/Documents/march_client_for_server.jks" 
    
    keystoreFile="/Users/march/Documents/march_server.jks" 
    keystorePass="123456" 

    disableUploadTimeout="true" 
    enableLookups="true" 
    SSLEnabled="true" 
    acceptCount="100"  
    maxSpareThreads="75" 
    maxThreads="200" 
    minSpareThreads="5" 
    protocol="org.apache.coyote.http11.Http11NioProtocol" 
    scheme="https" 
    secure="true" 
    port="8443" 
    sslProtocol="TLS"/>
複製程式碼

此時瀏覽器已經不能訪問

Android 進行 Https 訪問

如果你的證照是購買的 CA 簽發的證照,是可以直接進行 https 訪問的,不需要做什麼特殊處理,下面主要介紹使用自簽名證照的情況。

啟用雙向驗證時,Android 客戶端也不能直接使用 march_client.jks 需要轉為 bks 檔案,使用下面的工具。jks 轉 bks 工具

注:這部分不是說如何發請求,只是討論怎麼配置證照和金鑰對去發起 Https 訪問。

Android 中進行 Https 訪問,主要牽扯到以下幾個關鍵類:

  1. TrustManagerFactory,它主要是用來匯入自簽名證照,用來驗證來自伺服器的連線。
  2. KeyManagerFactory,當開啟雙向驗證時,用來匯入客戶端的金鑰對。
  3. SSLContextSSL 上下文,使用上面的兩個類進行初始化,就是個上下文環境。

? 都讓開,我要貼程式碼了!

SSLContext

為了簡單起見,我們先來看看如何生成 SSLContext

/**
 * 建立 SSLContext 
 * @param keyManagerFactory 用於雙向驗證,不需要可以直接為空
 * @param trustManagerFactory 用於匯入證照
 * @return SSLContext
 */
private SSLContext getSSLContext(@Nullable KeyManagerFactory keyManagerFactory,
        TrustManagerFactory trustManagerFactory)
        throws NoSuchAlgorithmException, KeyManagementException {
    if (trustManagerFactory == null)
        return null;
    SSLContext sslContext = SSLContext.getInstance("TLS");
    KeyManager[] keyManagers = null;
    if (keyManagerFactory != null) {
        keyManagers = keyManagerFactory.getKeyManagers();
    }
    sslContext.init(keyManagers, trustManagerFactory.getTrustManagers(), new SecureRandom());
    return sslContext;
}
複製程式碼

TrustManagerFactory

匯入客戶端證照,生成 TrustManagerFactory

/**
 * 匯入客戶端證照,生成 TrustManagerFactory
 * @param serverCertInputStreams 證照的輸入流
 * @return TrustManagerFactory
 */
private TrustManagerFactory getTrustManagerFactory(InputStream... serverCertInputStreams)
        throws KeyStoreException, CertificateException, NoSuchAlgorithmException, IOException {
    if (serverCertInputStreams == null || serverCertInputStreams.length == 0) {
        return null;
    }
    CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
    // 為證照設定一個keyStore,並將證照放入 keyStore 中
    KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
    keyStore.load(null, null);
    int index = 0;
    for (InputStream inputStream : serverCertInputStreams) {
        String alias = Integer.toString(index++);
        Certificate certificate = certificateFactory.generateCertificate(inputStream);
        keyStore.setCertificateEntry(alias, certificate);
    }
    // 建立 TrustManagerFactory
    TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
    trustManagerFactory.init(keyStore);
    TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
    if (trustManagers.length != 1 || !(trustManagers[0] instanceof X509TrustManager)) {
        throw new IllegalStateException("Unexpected default trust managers:"
                + Arrays.toString(trustManagers));
    }
    return trustManagerFactory;
}
複製程式碼

KeyManagerFactory

雙向驗證時,配置客戶端金鑰對,生成 KeyManagerFactory

/**
 * 雙向驗證時,配置客戶端金鑰對,生成 KeyManagerFactory
 *
 * @param clientCertInputStream 金鑰對輸入流
 * @param passWd                金鑰對密碼
 * @return KeyManagerFactory
 */
private KeyManagerFactory getKeyManagerFactory(InputStream clientCertInputStream, String passWd)
        throws KeyStoreException, CertificateException, NoSuchAlgorithmException, IOException, UnrecoverableKeyException {
    if (clientCertInputStream == null || passWd == null) {
        return null;
    }
    //本地證照 初始化keystore
    KeyStore clientKeyStore = KeyStore.getInstance(KeyStore.getDefaultType());
    clientKeyStore.load(clientCertInputStream, passWd.toCharArray());
    KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
    keyManagerFactory.init(clientKeyStore, passWd.toCharArray());
    return keyManagerFactory;
}
複製程式碼

Init Connection

這樣我們就拿到了已經生成好的 SSLContext,我們需要的 KeyManagerFactoryTrustManagerFactory 都已經加到 SSLContext 裡面了。

如果是用 HttpsURLConnection

connection.setSSLSocketFactory(sslContext.getSocketFactory());
複製程式碼

如果是用 OkHttp

// 這個方法已經過時了
okHttpClientBuilder.sslSocketFactory(sslContext.getSocketFactory());

// 新的方法需要一個 X509TrustManager,那我們就從 TrustManagerFactory 取出來給他
TrustManagerFactory trustManagerFactory = getTrustManagerFactory(serverCertInputStreams);
KeyManagerFactory keyManagerFactory = getKeyManagerFactory(clientCertInputStream, passWd);
if (trustManagerFactory != null) {
    X509TrustManager x509TrustManager = (X509TrustManager) trustManagerFactory.getTrustManagers()[0];
    SSLContext sslContext = getSSLContext(keyManagerFactory, trustManagerFactory);
    if (x509TrustManager != null && sslContext != null) {
        okHttpClientBuilder.sslSocketFactory(sslContext.getSocketFactory(), x509TrustManager);
    }
}
複製程式碼

HostnameVerifier

另外 HostnameVerifier 也是必要的,這個 HttpsURLConnectionOkHttp 沒啥差別

connection.setHostnameVerifier(new HostnameVerifier() {
    @Override
    public boolean verify(String hostname, SSLSession session) {
        return true;
    }
});

okHttpClientBuilder.hostnameVerifier(new HostnameVerifier() {
    @Override
    public boolean verify(String hostname, SSLSession session) {
        return true;
    }
});
複製程式碼

巨人的肩膀

CSDN 如何理解HTTP協議的 “無連線,無狀態” 特點?

知乎 一個故事讓你徹底理解 Https

簡書 HTTPS 是如何保證安全的?

個人部落格-餓了麼Android-聊聊 Android HTTPS 的使用姿勢

個人部落格-細說 CA 和證照

個人部落格-https詳解 概要介紹

CSDN-hongyang-Android Https 完全解析

阮一峰-SSL/TLS協議執行機制的概述

註腳

**訊息摘要(Message Digest)**

指的是將長度不固定的引數作為輸入引數,執行特定 hash 函式,生成固定長度的輸出,這個輸出就是訊息的摘要,常用演算法有 MD5SHA1,摘要演算法是單向不可逆的,即無法從摘要重新反向出原訊息的內容。

**信用背書**

票據的收款人或持有人在轉讓票據時,在票據背面簽名或書寫文句的手續。背書的人就會對這張支票負某種程度、類似擔保的償還責任。

**非對稱加密的兩種應用場景**
  1. 某使用者使用自己的私鑰對資料加密,任何人都可以使用公鑰對資料進行解密,因為私鑰只有該使用者持有,則說明該資料一定出自於該使用者。公眾可以用這一方法驗證內容是否完整,是否被篡改,接受者可以認定該內容出自該使用者,該使用者也無法抵賴,這被稱作數字簽名。
  2. 某使用者使用公開的公鑰對資料進行加密,那麼可以保證只有釋出公鑰的一方可以對資料進行解密,別人無法獲取資料的內容,保證資料傳遞的安全。

應對 CA 簽發證照權威性問題的解決方案

  1. Google 推動的 Certificate Transparency 技術,它旨在通過開放的審計和監控系統,提高 HTTPS 網站證照安全性。CT 技術能改善這種情況,但 CT 還沒有普及,現階段瀏覽器不能貿然阻斷沒有提供 SCT 資訊的 HTTPS 網站。CT 介紹

  2. HTTP Public Key Pinning 技術 HPKP 介紹

相關文章