首頁 > 軟體

Android Https證書過期的兩種解決方案

2022-12-25 14:03:30

應該有很多小夥伴遇到這樣一個問題,線上上已釋出的app裡,關於https的cer證書過期,從而導致app所有網路請求失效無法使用。

這個時候有人就要說了,應急釋出一個已更新最新cer證書的apk不就完事了麼,其實沒那麼簡單,iOS還好可以通過appstore提供的api查詢到新版本,但android就不一樣了,需要呼叫自己Server端提供的api介面查詢到新版本,並獲取apk下載路徑,問題是https都不能存取了,如何請求到版本資訊呢?下面提供兩種常見的解決方案:

方案一

將版本資訊介面讓後臺改成http(不推薦,後臺因素不可控),或者將本地https的設定一個不安全校驗(推薦)。

private static OkHttpClient newOkHttpClient(int timeout){
 
        HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
        logging.setLevel(HttpLoggingInterceptor.Level.BODY);
 
        return new OkHttpClient.Builder()
                .addInterceptor(new RequestInfoInterceptor())
                //.addInterceptor(logging)
                .addNetworkInterceptor(new TokenHeaderInterceptor())
                .sslSocketFactory(Certificate.getSSLSocketFactory())
                //設定不安全校驗
                .hostnameVerifier(Certificate.getUnSafeHostnameVerifier())
                .readTimeout(timeout, TimeUnit.SECONDS)
                .writeTimeout(timeout, TimeUnit.SECONDS)
                .build();
    }
 
    /**
     *獲取HostnameVerifier 
     */
    public static HostnameVerifier getUnSafeHostnameVerifier() {
        HostnameVerifier hostnameVerifier = new HostnameVerifier() {
            @Override
            public boolean verify(String s, SSLSession sslSession) {
                return true;
            }
        };
        return hostnameVerifier;
    }

方案二

將xxx.cer證書改成動態讀取(以檔案的方式從app沙盒裡面讀取即可),在https證書即將過期時,從伺服器下載最新的cer證書更新到沙盒裡面,App每次初始化網路請求時讀取sdcard最新的證書檔案,這樣App就永遠不會出現https證書過期導致無法使用的問題,流程圖如下。

下面是一些關鍵的程式碼:

    private static OkHttpClient newOkHttpClient(int timeout){
 
        HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
        logging.setLevel(HttpLoggingInterceptor.Level.BODY);
 
        return new OkHttpClient.Builder()
                .addInterceptor(new RequestInfoInterceptor())
                //.addInterceptor(logging)
                .addNetworkInterceptor(new TokenHeaderInterceptor())
                .sslSocketFactory(Certificate.getSSLSocketFactory(BaseApplcation.myApp, new String[]{"/sdcard/xxx.cer"}))
                .hostnameVerifier(Certificate.getUnSafeHostnameVerifier())
                .readTimeout(timeout, TimeUnit.SECONDS)
                .writeTimeout(timeout, TimeUnit.SECONDS)
                .build();
    }
  
    /**
     * 帶證書的,從本地檔案讀取
     * @param context
     * @param certificatesFiles  本地檔案(通過下載到本地)
     * @return
     */
    public static SSLSocketFactory getSSLSocketFactory(Context context, String[] certificatesFiles) {
        if (context == null) {
            throw new NullPointerException("context == null");
        }
        CertificateFactory certificateFactory;
        try {
            certificateFactory = CertificateFactory.getInstance("X.509");
            KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
            keyStore.load(null, null);
 
            for (int i = 0; i < certificatesFiles.length; i++) {
                InputStream certificate = new FileInputStream(certificatesFiles[i]);
                keyStore.setCertificateEntry(String.valueOf(i), certificateFactory.generateCertificate(certificate));
 
                if (certificate != null) {
                    certificate.close();
                }
            }
            SSLContext sslContext = SSLContext.getInstance("TLS");
            TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
            trustManagerFactory.init(keyStore);
            sslContext.init(null, trustManagerFactory.getTrustManagers(), new SecureRandom());
            return sslContext.getSocketFactory();
        } catch (Exception e) {
 
        }
        return null;
    }
 
  /**
     * 帶證書的,從raw資源中讀取
     * @param context
     * @param certificates  rawIds
     * @return
     */
    public static SSLSocketFactory getSSLSocketFactory(Context context, int[] certificates) {
        if (context == null) {
            throw new NullPointerException("context == null");
        }
        CertificateFactory certificateFactory;
        try {
            certificateFactory = CertificateFactory.getInstance("X.509");
            KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
            keyStore.load(null, null);
 
            for (int i = 0; i < certificates.length; i++) {
                InputStream certificate = context.getResources().openRawResource(certificates[i]);
                keyStore.setCertificateEntry(String.valueOf(i), certificateFactory.generateCertificate(certificate));
 
                if (certificate != null) {
                    certificate.close();
                }
            }
            SSLContext sslContext = SSLContext.getInstance("TLS");
            TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
            trustManagerFactory.init(keyStore);
            sslContext.init(null, trustManagerFactory.getTrustManagers(), new SecureRandom());
            return sslContext.getSocketFactory();
        } catch (Exception e) {
 
        }
        return null;
    }

到此這篇關於Android Https證書過期的解決方案的文章就介紹到這了,更多相關Android Https證書過期內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com