(Note) 淺析Https

Thanks

HTTPS理論基礎及其在Android中的最佳實踐
聊聊HTTPS和SSL/TLS協議

理解HTTPS

HTTPS概述

HTTPS是建立在HTTP的基礎上,Http是一個網絡協議,用于傳輸內容,我們知道HTTP的通信過程大致如下:

8.png

Http基于4層網絡模型:

    ┌────------────┐┌─┬─┬─-┬─┬─-┬─┬─-┬─┬─-┬─┬─-┐
  │        ││D│F│W│F│H│G│T│I│S│U│ │
  │        ││N│I│H│T│T│O│E│R│M│S│其│
  │第四層,應用層 ││S│N│O│P│T│P│L│C│T│E│ │
  │        ││ │G│I│ │P│H│N│ │P│N│ │
  │        ││ │E│S│ │ │E│E│ │ │E│它│
  │        ││ │R│ │ │ │R│T│ │ │T│ │
  └───────------─┘└─┴─┴─-┴─┴─-┴─┴─-┴─┴─-┴─┴-─┘
  ┌───────-----─┐┌─────────-------┬──--------─────────┐
  │第三層,傳輸層 ││   TCP   │    UDP    │
  └───────-----─┘└────────-------─┴──────────--------─┘
  ┌───────-----─┐┌───----──┬───---─┬────────-------──┐
  │        ││     │ICMP│          │
  │第二層,網絡層 ││     └──---──┘          │
  │        ││       IP            │
  └────────-----┘└────────────────────-------------─-┘
  ┌────────-----┐┌─────────-------┬──────--------─────┐
  │第一層,網絡接口││ARP/RARP │    其它     │
  └────────------┘└─────────------┴─────--------──────┘
       TCP/IP四層參考模型

從層級上我們可以發現,應用層產生的數據,直接經由傳輸層直接傳輸,存在一個很大的問題,安全性。原本的Http就是傳輸明文的,數據一經攔截就很容易被別人盜取信息。那怎么解決呢?HTTPS的方法是,對傳輸的數據進行加密,在應用層和傳輸層的中間加一層,S層: SSL/TLS,Secure Sockets Layer 安全套接層 / Transport Layer Security 傳輸層安全協議,這一層使用的主要是 SSL/TLS 技術,這兩個協議其實就是安全加密算法的不同:

    ┌────------────┐┌─┬─┬─-┬─┬─-┬─┬─-┬─┬─-┬─┬─-┐
  │        ││D│F│W│F│H│G│T│I│S│U│ │
  │        ││N│I│H│T│T│O│E│R│M│S│其│
  │第四層,應用層 ││S│N│O│P│T│P│L│C│T│E│ │
  │        ││ │G│I│ │P│H│N│ │P│N│ │
  │        ││ │E│S│ │ │E│E│ │ │E│它│
  │        ││ │R│ │ │ │R│T│ │ │T│ │
  └───────------─┘└─┴─┴─-┴─┴─-┴─┴─-┴─┴─-┴─┴-─┘

              ┌───────-----─┐
            │SSL/TLS     │       
            └───────-----─┘

  ┌───────-----─┐┌─────────-------┬──--------─────────┐
  │第三層,傳輸層 ││   TCP   │    UDP    │
  └───────-----─┘└────────-------─┴──────────--------─┘
  ┌───────-----─┐┌───----──┬───---─┬────────-------──┐
  │        ││     │ICMP│          │
  │第二層,網絡層 ││     └──---──┘          │
  │        ││       IP            │
  └────────-----┘└────────────────────-------------─-┘
  ┌────────-----┐┌─────────-------┬──────--------─────┐
  │第一層,網絡接口││ARP/RARP │    其它     │
  └────────------┘└─────────------┴─────--------──────┘
       TCP/IP四層參考模型
對稱加密算法

既然加密,那怎么一個規則呢?加密,在我們的理解是這樣的:

9.png

用一個密碼/密鑰,用某種算法對明文進行加密,得到密文,解密也容易:

10.png

像上面這樣,用同一個密碼/密鑰進行加密和解密的,就是對稱加密算法,因為其密碼/密鑰是一樣的,所以名曰為對稱。但如果HTTPS中使用這種算法的話,就需要通信雙方知道密鑰,這樣就必須在通信的時候,先把密鑰發給對方,但這樣,黑客若截獲這密碼,等于沒用。

非對稱加密算法

“非對稱加密技術”,意思就是說:“加密”和“解密”使用不同的密鑰。其基本原理,就是大數的因式分解。這里就不展開了,密碼學的東西,很神奇。因為有兩個不同的密鑰,我們命名為公鑰和私鑰,公鑰是可以對外公開的,私鑰是自己保管的,用公鑰或私鑰中的任何一個進行加密,用另一個進行解密。 加密和解密就變成這樣:

明文 + 加密算法 + 公鑰 => 密文, 
密文 + 解密算法 + 私鑰 => 明文 
11.png

或者是這樣:

明文 + 加密算法 + 私鑰 => 密文, 
密文 + 解密算法 + 公鑰 => 明文 

總結來說,兩個密鑰皆可加密,加密后只有由另一個密鑰解密。

HTTPS中加密算法

非對稱加密很棒,但是呢,效率不高,速度慢,對稱加密雖然安全性不高,但是效率高啊。怎么選擇呢?小孩子才做選擇,大人全都要。HTTPS結合了兩種加密算法的優勢,加密解密變成這樣:

13.png

這個過程涉及到四個密鑰:私鑰,公鑰,對稱加密的Key(這里稱為KeyX),公鑰加密KeyX后的KeyY。首先客戶端會得到服務器發來的公鑰,然后,客戶端會隨機生成一個對稱加密用的Key,這里稱為KeyX,用KeyX對我們要傳輸的明文進行對稱加密,因為明文可能很多,所以這里用對稱加密,就效率高很多,得到對稱加密的密文,然后用公鑰對KeyX進行非對此加密得到KeyY,然后一并傳輸密文和KeyY給服務器。想要解釋密文,就得先得到KeyX,想要得到KeyX,就得有密鑰,完美。所以只能擁有密鑰的服務器能得到明文。

具體的HTTPS請求實際可細分為一下步驟:(摘自大神博客)

  1. 客戶端向服務器發起HTTPS請求,連接到服務器的443端口。
  2. 服務器端有一個密鑰對,即公鑰和私鑰,是用來進行非對稱加密使用的,服務器端保存著私鑰,不能將其泄露,公鑰可以發送給任何人。
  3. 服務器將自己的公鑰發送給客戶端。
  4. 客戶端收到服務器端的公鑰之后,會對公鑰進行檢查,驗證其合法性。如果發現發現公鑰有問題,那么HTTPS傳輸就無法繼續。嚴格的說,這里應該是驗證服務器發送的數字證書的合法性。如果公鑰合格,那么客戶端會生成一個隨機值,這個隨機值就是用于進行對稱加密的密鑰,我們將該密鑰稱之為client key,即客戶端密鑰,這樣在概念上和服務器端的密鑰容易進行區分。然后用服務器的公鑰對客戶端密鑰進行非對稱加密,這樣客戶端密鑰就變成密文了,至此,HTTPS中的第一次HTTP請求結束。
  5. 客戶端會發起HTTPS中的第二個HTTP請求,將加密之后的客戶端密鑰發送給服務器。
  6. 服務器接收到客戶端發來的密文之后,會用自己的私鑰對其進行非對稱解密,解密之后的明文就是客戶端密鑰,然后用客戶端密鑰對數據進行對稱加密,這樣數據就變成了密文。
  7. 然后服務器將加密后的密文發送給客戶端。
  8. 客戶端收到服務器發送來的密文,用客戶端密鑰對其進行對稱解密,得到服務器發送的數據。這樣HTTPS中的第二個HTTP請求結束,整個HTTPS傳輸完成。

數字證書

我們拿到的公鑰怎么確保真的是服務器的公鑰呢?黑客有可能中途篡改公鑰,將其改成黑客自己的。摘個例子:

假設一個鎮里面有兩個人A和B,A是個富豪,B想向A借錢,但是A和B不熟,怕B借了錢之后不還。這時候B找到了鎮長,鎮長給B作擔保,告訴A說:“B人品不錯,不會欠錢不還的,你就放心借給他吧。” A聽了這話后,心里想:“鎮長是全鎮最德高望重的了,他說B沒問題的話那就沒事了,我就放心了”。 于是A相信B的為人,把錢借給了B。

類似地,公鑰需要一個擔保人:證書認證中心(Certificate Authority),簡稱CA。CA本身有一對公鑰和私鑰,CA會用CA自己的私鑰對要進行認證的公鑰進行非對稱加密,此處待認證的公鑰就相當于是明文,加密完之后,得到的密文再加上證書的過期時間、頒發給、頒發者等信息,就組成了數字證書。

Android-Retrofit 配置證書 訪問HTTPS

先把轉換后的cer文件放到 R.raw.

private SSLContext initCertificates(InputStream... certificates) {
    try {
        CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
        KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
        keyStore.load(null);
        int index = 0;
        for (InputStream certificate : certificates) {
            String certificateAlias = Integer.toString(index++);
            keyStore.setCertificateEntry(certificateAlias, certificateFactory.generateCertificate(certificate));
            try {
                if (certificate != null)
                    certificate.close();
            } catch (IOException ignored) { }
        }
        SSLContext sslContext = SSLContext.getInstance("TLS");
        TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
        trustManagerFactory.init(keyStore);
        sslContext.init(null, trustManagerFactory.getTrustManagers(), new SecureRandom());
        return sslContext;
    } catch (Exception e) {
        e.printStackTrace();
        return null;
    }
}
public void init(Context context) {
    InputStream inputStream = context.getResources().openRawResource(R.raw.https);
    sslContext = initCertificates(inputStream);
}

調用:

private HttpsContract getBaseHttpProtocol(SSLContext sslContext, String baseServer) {
    OkHttpClient client=new OkHttpClient.Builder()
            .sslSocketFactory(sslContext.getSocketFactory())
            .hostnameVerifier(new SafeHostnameVerifier())
            .build();
    Retrofit retrofit = new Retrofit.Builder()
            .baseUrl(baseServer)
            .addConverterFactory(ScalarsConverterFactory.create())
            .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
            .client(client)
            .build();
    return retrofit.create(HttpsContract.class);
}
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容