Okhttp3 - 接受所有证书并使用certificatePinner [英] Okhttp3 - Accept all certificates and use a certificatePinner

查看:636
本文介绍了Okhttp3 - 接受所有证书并使用certificatePinner的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试固定服务器的自签名证书。
我的OkHttpClient有两个参数,第一个是ssl Socket Factory:

I'm trying to pin my server's self-signed certificate. My OkHttpClient takes two parameters, the first one is the ssl Socket Factory :

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()被调用:

Note: if I don't add a certificatePinner, then everything works fine. The problem is that when the request gets executed, CertificatePinner.check() gets called:

if (pins.isEmpty()) return;

显然,如果我设置了一个(非空)certificatePinner,该方法不会就此止步并将继续。然后继续检查 至少有一个固定为我的主机名的证书是可信证书

Obviously, if I do set a (non-empty) certificatePinner, the method won't stop there and will continue. It then goes on to check that "at least one of the certificates pinned for my hostname is a trusted certificate".

问题是我在getAcceptedIssuers中为我的TrustManager传递了一个空数组 - 这意味着自签名证书将触发异常,因为它在getAcceptedIssues中没有被明确信任。似乎无法在getAcceptedIssuers中固定不受信任的证书。

The problem is that I passed an empty array in getAcceptedIssuers for my TrustManager - meaning the self-signed cert will trigger an exception since it hasn't been explicitly trusted in "getAcceptedIssues". Seems like it's impossible to pin a certificate that isn't trusted explicitly in "getAcceptedIssuers".

有没有办法解决这个问题?它是按设计的吗?

Is there any way to get around that? Is it by design?

这就是我构建我的OkHttpClient的方式:

This is how I build my OkHttpClient :

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


推荐答案

TrustManager,CertificatePinner和Hostname验证都有所不同,但重要的事情。如果您想使用自签名证书但仍然具有安全性,而不是纯粹为了便于本地开发的自签名证书,那么您可能想要创建一个有效的TrustManager。

The TrustManager, CertificatePinner and Hostname verification all do different but important things. If you want to use self-signed certificates but still have security, as opposed to self-signed certificates purely for ease of local development then you probably want to create a valid 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;
  }

这将从加载系统证书开始,因此您的客户仍然可以用于加载外部托管的图像等。

This will start off with the system certificates loaded, so your client can still be used to load externally hosted images etc.

然后,您可以使用CertificatePinner要求只为您的域使用您信任的自签名证书。

Then on top of that you can use CertificatePinner to require that only your trusted self-signed certificates are used for your domain.

这篇关于Okhttp3 - 接受所有证书并使用certificatePinner的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆