2017-02-17 53 views
1

我試圖固定我的服務器的自簽名證書。 我OkHttpClient有兩個參數,第一個是SSL套接字工廠:Okhttp3 - 接受所有證書並使用certificatePinner

final TrustManager[] trustAllCerts = new TrustManager[] { 
     new X509TrustManager() { 
      @SuppressLint("TrustAllX509TrustManager") 
      @Override 
      public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {} 

      @SuppressLint("TrustAllX509TrustManager") 
      @Override 
      public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {} 

      @Override 
      public java.security.cert.X509Certificate[] getAcceptedIssuers() { 
        return new X509Certificate[0]; 
      } 
     } 
    }; 

// Install the all-trusting trust manager 
SSLContext sslContext; 
try { 
    sslContext = SSLContext.getInstance("SSL"); 
    sslContext.init(null, trustAllCerts, new java.security.SecureRandom()); 
} catch (NoSuchAlgorithmException | KeyManagementException e) { 
    e.printStackTrace(); 
    FirebaseCrash.report(e); 
    return null; 
} 

// Create an ssl socket factory with our all-trusting manager 
final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory(); 

二是證書平納:

new CertificatePinner.Builder() 
    .add("bogus.com", "sha1/BOGUS") 
    .build() 

注:如果我不加certificatePinner,則一切正常精細。問題是,該請求被執行時,CertificatePinner.check()被調用:

if (pins.isEmpty()) return; 

顯然,如果我設置一個(非空)certificatePinner,該方法不會停在那裏,並會繼續。然後它繼續檢查「至少一個固定我的主機名的證書是可信證書」

問題是我在我的TrustManager中傳遞了getAcceptedIssuers中的空數組 - 意味着自簽名證書將觸發異常,因爲它在「getAcceptedIssues」中沒有被明確信任。似乎不可能在「getAcceptedIssuers」中明確表示不可信任的證書。

有什麼辦法可以解決這個問題嗎?它是否由設計?

這是我建立我的OkHttpClient:

OkHttpClient client = new OkHttpClient.Builder() 
    .sslSocketFactory(sslSocketFactory, (X509TrustManager) trustAllCerts[0]) 
    .certificatePinner(certPinner) 
    .readTimeout(10, TimeUnit.SECONDS) 
    .connectTimeout(10, TimeUnit.SECONDS) 
    .build(); 

回答

2

的的TrustManager,CertificatePinner和主機名驗證都做不同的,但重要的事情。如果您想使用自簽名證書,但仍具有安全性,純粹爲了便於本地開發,而不是自簽名證書,那麼您可能需要創建一個有效的TrustManager。

例如https://github.com/yschimke/oksocial/blob/3757196cde420b9d0fe37cf385b66f4cdafb1ae1/src/main/java/com/baulsupp/oksocial/security/CertificateUtils.java#L19

public static X509TrustManager load(List<File> serverCerts) 
     throws NoSuchAlgorithmException, KeyStoreException, IOException, CertificateException { 
    return trustManagerForKeyStore(keyStoreForCerts(serverCerts)); 
    } 

    public static X509TrustManager trustManagerForKeyStore(KeyStore ks) 
     throws NoSuchAlgorithmException, KeyStoreException { 
    TrustManagerFactory tmf = 
     TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); 

    tmf.init(ks); 

    return (X509TrustManager) tmf.getTrustManagers()[0]; 
    } 

    public static KeyStore keyStoreForCerts(List<File> serverCerts) 
     throws CertificateException, KeyStoreException, IOException, NoSuchAlgorithmException { 
    CertificateFactory cf = CertificateFactory.getInstance("X.509"); 

    KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType()); 
    ks.load(null); 

    for (int i = 0; i < serverCerts.size(); i++) { 
     try (InputStream is = new FileInputStream(serverCerts.get(i))) { 
     X509Certificate caCert = (X509Certificate) cf.generateCertificate(is); 
     ks.setCertificateEntry("cacrt." + i, caCert); 
     } 
    } 
    return ks; 
    } 

這將加載的系統證書開始,讓你的客戶仍然可以用來加載外部託管的圖片等

然後最重要的是你可以使用CertificatePinner要求,只有你受信任的自簽名證書用於您的域。

+0

你提供的代碼絕對幫了我,雖然它不完全回答我原來的問題。感謝您的幫助,我最終創建了一個有效的TrustManager。 – geecko

+0

是的,我試圖回答我認爲你正在嘗試做的事情,添加一個自簽名證書,以便你有一個安全的連接,但針對這一點。接受所有證書然後嘗試安裝並不是典型的用例。 –

1
private static OkHttpClient getUnsafeOkHttpClient() { 
    try { 
    // Create a trust manager that does not validate certificate chains 
    final TrustManager[] trustAllCerts = new TrustManager[] { 
     new X509TrustManager() { 
      @Override 
      public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException { 
      } 

      @Override 
      public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException { 
      } 

      @Override 
      public java.security.cert.X509Certificate[] getAcceptedIssuers() { 
      return new java.security.cert.X509Certificate[]{}; 
      } 
     } 
    }; 

    // Install the all-trusting trust manager 
    final SSLContext sslContext = SSLContext.getInstance("SSL"); 
    sslContext.init(null, trustAllCerts, new java.security.SecureRandom()); 
    // Create an ssl socket factory with our all-trusting manager 
    final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory(); 

    OkHttpClient.Builder builder = new OkHttpClient.Builder(); 
    builder.sslSocketFactory(sslSocketFactory, (X509TrustManager)trustAllCerts[0]); 
    builder.hostnameVerifier(new HostnameVerifier() { 
     @Override 
     public boolean verify(String hostname, SSLSession session) { 
     return true; 
     } 
    }); 

    OkHttpClient okHttpClient = builder 
     .connectTimeout(15, TimeUnit.SECONDS) 
     .writeTimeout(15, TimeUnit.SECONDS) 
     .readTimeout(15, TimeUnit.SECONDS) 
     .build(); 
    return okHttpClient; 
    } catch (Exception e) { 
    throw new RuntimeException(e); 
    } 
} 
+0

雖然這個答案可能是正確和有用的,但如果[包括一些解釋](http://meta.stackexchange.com/q/114762/159034)解釋它如何幫助解決問題,它是首選。如果有變化(可能不相關)導致其停止工作,讀者需要了解它曾經如何工作,這在未來變得特別有用。 –

+0

@KevinBrown你是對的,只是想幫忙,但是真的讓這裏的人很不高興。 – samcpp

+2

需要OkHttp3的示例代碼 – Lunatikul