您好,登錄后才能下訂單哦!
這篇文章將為大家詳細講解有關Android如何使用OkHttp請求自簽名的https網站,小編覺得挺實用的,因此分享給大家做個參考,希望大家閱讀完這篇文章后可以有所收獲。
很多公司考慮到安全問題,項目中都采用https加密協議進行數據傳輸。但是一些公司又不想花一筆錢去CA申請證書,所以就采用自簽名的證書。
OkHttp默認是可以訪問通過CA認證的HTTPS鏈接,例如百度首頁也是https鏈接(https://www.baidu.com/)。但是如果是你們公司自簽名(即自己用keytool生成的證書,而不是采用通過CA認證的證書)的服務器,OkHttp是無法訪問的,例如訪問12306網站(https://kyfw.12306.cn/otn/),會報如下錯誤:
HTTPS的工作原理
HTTPS在傳輸數據之前需要客戶端(瀏覽器)與服務端(網站)之間進行一次握手,在握手過程中將確立雙方加密傳輸數據的密碼信息。握手過程的簡單描述如下:
瀏覽器將自己支持的一套加密算法、HASH算法發送給網站。
網站從中選出一組加密算法與HASH算法,并將自己的身份信息以證書的形式發回給瀏覽器。證書里面包含了網站地址,加密公鑰,以及證書的頒發機構等信息。
瀏覽器獲得網站證書之后,開始驗證證書的合法性,如果證書信任,則生成一串隨機數字作為通訊過程中對稱加密的秘鑰。然后取出證書中的公鑰,將這串數字以及HASH的結果進行加密,然后發給網站。
網站接收瀏覽器發來的數據之后,通過私鑰進行解密,然后HASH校驗,如果一致,則使用瀏覽器發來的數字串使加密一段握手消息發給瀏覽器。
瀏覽器解密,并HASH校驗,沒有問題,則握手結束。接下來的傳輸過程將由之前瀏覽器生成的隨機密碼并利用對稱加密算法進行加密。
握手過程中如果有任何錯誤,都會使加密連接斷開,從而阻止了隱私信息的傳輸。
使用OKHTTP請求自簽名的https服務器數據
以下我們使用12306網站為例
1. 首先去12306網站首頁下載證書 http://www.12306.cn/
2. 將下載的證書srca.cer放到工程的assets文件夾下。
3. 添加HTTPS工具類
package com.alpha58.okhttp; import android.content.Context; import java.io.IOException; import java.io.InputStream; import java.security.GeneralSecurityException; import java.security.KeyStore; import java.security.cert.Certificate; import java.security.cert.CertificateFactory; import java.util.Arrays; import java.util.Collection; import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSocketFactory; import javax.net.ssl.TrustManager; import javax.net.ssl.TrustManagerFactory; import javax.net.ssl.X509TrustManager; import okhttp3.OkHttpClient; /** * Created by admin on 2017/03/12. */ public final class HTTPSUtils { private OkHttpClient client; public Context mContext; /** * 獲取OkHttpClient實例 * @return */ public OkHttpClient getInstance() { return client; } /** * 初始化HTTPS,添加信任證書 * @param context */ public HTTPSUtils(Context context) { mContext = context; X509TrustManager trustManager; SSLSocketFactory sslSocketFactory; final InputStream inputStream; try { inputStream = mContext.getAssets().open("srca.cer"); // 得到證書的輸入流 try { trustManager = trustManagerForCertificates(inputStream);//以流的方式讀入證書 SSLContext sslContext = SSLContext.getInstance("TLS"); sslContext.init(null, new TrustManager[]{trustManager}, null); sslSocketFactory = sslContext.getSocketFactory(); } catch (GeneralSecurityException e) { throw new RuntimeException(e); } client = new OkHttpClient.Builder() .sslSocketFactory(sslSocketFactory, trustManager) .build(); } catch (IOException e) { e.printStackTrace(); } } /** * 以流的方式添加信任證書 */ /** * Returns a trust manager that trusts {@code certificates} and none other. HTTPS services whose * certificates have not been signed by these certificates will fail with a {@code * SSLHandshakeException}. * <p> * <p>This can be used to replace the host platform's built-in trusted certificates with a custom * set. This is useful in development where certificate authority-trusted certificates aren't * available. Or in production, to avoid reliance on third-party certificate authorities. * <p> * <p> * <h4>Warning: Customizing Trusted Certificates is Dangerous!</h4> * <p> * <p>Relying on your own trusted certificates limits your server team's ability to update their * TLS certificates. By installing a specific set of trusted certificates, you take on additional * operational complexity and limit your ability to migrate between certificate authorities. Do * not use custom trusted certificates in production without the blessing of your server's TLS * administrator. */ private X509TrustManager trustManagerForCertificates(InputStream in) throws GeneralSecurityException { CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509"); Collection<? extends Certificate> certificates = certificateFactory.generateCertificates(in); if (certificates.isEmpty()) { throw new IllegalArgumentException("expected non-empty set of trusted certificates"); } // Put the certificates a key store. char[] password = "password".toCharArray(); // Any password will work. KeyStore keyStore = newEmptyKeyStore(password); int index = 0; for (Certificate certificate : certificates) { String certificateAlias = Integer.toString(index++); keyStore.setCertificateEntry(certificateAlias, certificate); } // Use it to build an X509 trust manager. KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance( KeyManagerFactory.getDefaultAlgorithm()); keyManagerFactory.init(keyStore, password); 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 (X509TrustManager) trustManagers[0]; } /** * 添加password * @param password * @return * @throws GeneralSecurityException */ private KeyStore newEmptyKeyStore(char[] password) throws GeneralSecurityException { try { KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); // 這里添加自定義的密碼,默認 InputStream in = null; // By convention, 'null' creates an empty key store. keyStore.load(in, password); return keyStore; } catch (IOException e) { throw new AssertionError(e); } } }
4.代碼中請求
public void getHttpsHtml(View view) { Request request = new Request.Builder() .url("https://kyfw.12306.cn/otn/") .build(); HTTPSUtils httpsUtils = new HTTPSUtils(this); httpsUtils.getInstance().newCall(request).enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { System.out.println("--------------onFailure--------------" + e.toString()); } @Override public void onResponse(Call call, Response response) throws IOException { System.out.println("--------------onResponse--------------" + response.body().string()); } }); }
5. 最后能打印出這些信息就說明請求成功啦!
注意:別忘了加權限和依賴okhttp庫
關于“Android如何使用OkHttp請求自簽名的https網站”這篇文章就分享到這里了,希望以上內容可以對大家有一定的幫助,使各位可以學到更多知識,如果覺得文章不錯,請把它分享出去讓更多的人看到。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。