android開發中okhttp實現https請求

android開發中okhttp實現https請求。

定義:
HTTPS全稱為Hypertext Transfer Protocol over Secure Socket Layer
中文含義為“超文本傳輸協議在安全加密字層”
簡單來說就是加密數據傳輸和安全連接。https和http有什麼區別
在HTTP的之下加入瞭SSL (Secure Socket Layer),安全的基礎就靠SSL。
SSL位於TCP/IP和HTTP協議之間

https與http的區別:

●https更安全

HTTPS協議是由SSL+HTTP協議構建的可進行加密傳輸、身份認證的網絡協議,要比http協議安全。

●https需要申請證書

https協議需要到ca申請證書,一般免費證書很少,需要交費,費用大概與.COM域名差不多,每年需要交大約幾十元的費用。而常見的http協議則沒有這一項;

●端口不同

http使用的是大傢最常見的80端口,而https連接使用的是443端口;

●狀態不同

http的連接很簡單,是無狀態的。而HTTPS協議是由SSL+HTTP協議構建的可進行加密傳輸、身份認證的網絡協議,要比http協議安全

google官方推薦的android網絡請求框架okhttp已經集成瞭https的使用方法,我們隻需要按照api去調用即可。

使用okhttp實現https請求

首先要搞清楚https的請求需要什麼,可以從上面描述中看出,我們需要一份ca證書。
購買的證書,格式為.pfx,帶有公鑰和私鑰,附帶一個密碼。還有一種格式為.cer的證書,這種證書是沒有私鑰的。
服務器會將證書配置到tomcat中,客戶端則存放在本地,app啟動的時候加載進去。

.pfx格式和.cer格式的區別:

1.帶有私鑰的證書
  由Public Key Cryptography Standards #12,PKCS#12標準定義,包含瞭公鑰和私鑰的二進制格式的證書形式,以pfx作為證書文件後綴名。
  
2.二進制編碼的證書
  證書中沒有私鑰,DER 編碼二進制格式的證書文件,以cer作為證書文件後綴名。

3.Base64編碼的證書
證書中沒有私鑰,BASE64 編碼格式的證書文件,也是以cer作為證書文件後綴名。

更多具體區別:
.pfx格式和.cer格式的區別

在okhttp中配置ca證書:
將ca證書放在本地,這裡我們使用.pfx格式的證書srca.pfx:
這裡寫圖片描述

單向驗證

雖然我使用的是二次封裝okhttp的retrofit,但是這個配置還是屬於okhttp的。

有兩種寫法,先展示一種接近okhttp官方寫法的方法,官方api寫法不夠簡潔

    /**
     * 設置ihttps證書驗證
     */
    private void setCertificates(Context context) {
        try {
            //將ca證書導入輸入流
            InputStream inputStream = context.getResources().openRawResource(R.raw.aaa);

            //keystore添加證書內容和密碼
            KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
            keyStore.load(inputStream, CLIENT_KET_PASSWORD.toCharArray());

            //證書工廠類,生成證書
            CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
            //生成證書,添加別名
            keyStore.setCertificateEntry("test1", certificateFactory.generateCertificate(inputStream));

            //信任管理器工廠
            TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
            trustManagerFactory.init(keyStore);

            //構建一個ssl上下文,加入ca證書格式,與後臺保持一致
            SSLContext sslContext = SSLContext.getInstance("TLS");
            //參數,添加受信任證書和生成隨機數
            sslContext.init(null, trustManagerFactory.getTrustManagers(), new SecureRandom());

            //獲得scoket工廠
            SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
            mOkHttpClient.sslSocketFactory(sslSocketFactory);

            //設置ip授權認證:如果已經安裝該證書,可以不設置,否則需要設置
            mOkHttpClient.hostnameVerifier(new HostnameVerifier() {
                @Override
                public boolean verify(String hostname, SSLSession session) {
                    return true;
                }
            });
            inputStream.close();
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

第二種寫法,同樣有效

     /**
     * 設置ihttps證書驗證
     */
    private void setCertificates(Context context) {
        try {
            //將ca證書導入輸入流
            InputStream inputStream = context.getResources().openRawResource(R.raw.aaa);

            //keystore添加證書內容和密碼
            KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
            keyStore.load(inputStream, CLIENT_KET_PASSWORD.toCharArray())

            //key管理器工廠
            KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
            keyManagerFactory.init(keyStore, CLIENT_KET_PASSWORD.toCharArray());

            //構建一個ssl上下文,加入ca證書格式,與後臺保持一致
            SSLContext sslContext = SSLContext.getInstance("TLS");

            //參數,添加受信任證書和生成隨機數
            sslContext.init(keyManagerFactory.getKeyManagers(), null, new SecureRandom());

            //獲得scoket工廠
            SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
            mOkHttpClient.sslSocketFactory(sslSocketFactory);

            //設置ip授權認證:如果已經安裝該證書,可以不設置,否則需要設置
            mOkHttpClient.hostnameVerifier(new HostnameVerifier() {
                @Override
                public boolean verify(String hostname, SSLSession session) {
                    return true;
                }
            });
            inputStream.close();
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

值得註意的是,keystore的格式

 keystore拓展名對應格式:
            //JKS:.jks/.ks
            //JCEKS:.jce
            //PKCS12:.p12/.pfx
            //BKS:.bks
            //UBER:.ubr

所以,如果你的ca證書用的是.pfx,那麼可以這樣寫:

 KeyStore keyStore = KeyStore.getInstance("PKCS12");

如果是.cer的話那麼,就用

KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());

雙向驗證

雙向驗證的前提是,你的app同樣生成一個jks的密鑰文件,服務器那邊會同時有個“cer文件”與之對應。
假如:
客戶端的加密文件叫:test1.jks
服務器的加密文件叫:test2.cer

如何通過jks文件生成對應的cer文件?

接下來利用test1.jks來簽發證書,可以在android studio中,也可以在windows的dos中生成:
keytool -export -alias test1.jks
-file test2.cer
-keystore test1.jks
-storepass 123456

即可生成包含公鑰的證書test2.cer。

首先配置tomcat服務器:
Connector標簽,需要添加些屬性:

 
    clientAuth="true"
    truststoreFile="/Users/zhy/temp/test2.cer" 
    /> 

註意:如果tomcat中報錯keystore文件格式不正確,則我們再將cer文件轉換成jks文件:

keytool -import -alias test2.cer
-file test2.cer -keystore test3.jks

配置客戶端:

    /**
     * 設置ihttps證書驗證
     */
    private void setCertificates(Context context) {
        try {
            //將ca證書導入輸入流
            InputStream inputStream = context.getResources().openRawResource(R.raw.aaa);

            //keystore添加證書內容和密碼
            KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
            keyStore.load(inputStream, CLIENT_KET_PASSWORD.toCharArray());

            //證書工廠類,生成證書
            CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");

            //生成證書,添加別名
            keyStore.setCertificateEntry("test1", certificateFactory.generateCertificate(inputStream));

            //信任管理器工廠
            TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
            trustManagerFactory.init(keyStore);

            //雙向驗證,配置服務器驗證客戶端的證書
            InputStream inputStream1 = context.getResources().openRawResource(R.raw.bbb);
            KeyStore keyStore1 = KeyStore.getInstance(KeyStore.getDefaultType());
            keyStore1.load(inputStream1, CLIENT_KET_PASSWORD_1.toCharArray());
            KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
            keyManagerFactory.init(keyStore1, CLIENT_KET_PASSWORD_1.toCharArray());

            //構建一個ssl上下文,加入ca證書格式,與後臺保持一致
            SSLContext sslContext = SSLContext.getInstance("TLS");
            //參數,添加受信任證書和生成隨機數
            sslContext.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), new SecureRandom());
            //獲得scoket工廠
            SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
            mOkHttpClient.sslSocketFactory(sslSocketFactory);
            //設置ip授權認證:如果已經安裝該證書,可以不設置,否則需要設置
            mOkHttpClient.hostnameVerifier(new HostnameVerifier() {
                @Override
                public boolean verify(String hostname, SSLSession session) {
                    return true;
                }
            });
            inputStream.close();
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

註意:
Java平臺默認識別jks格式的證書文件,但是android平臺隻識別bks格式的證書文件,所以這裡還需要將jks的文件轉成bks。

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *