OkHttp 是否支持接受自签名 SSL 证书?

新手上路,请多包涵

我正在为拥有带有自签名 SSL 证书的服务器的客户工作。

我正在使用包装好的 OkHttp 客户端使用 Retrofit + CustomClient:

 RestAdapter restAdapter = new RestAdapter.Builder().setEndpoint(Config.BASE_URL + Config.API_VERSION)
    .setClient(new CustomClient(new OkClient(), context))
    .build();

OkHttp 是否支持默认调用自签名 SSL 证书服务器?

顺便一提。哪个客户端默认使用 Retrofit?我以为它是 OkHttp 但当我进一步研究时,我意识到我需要导入 OkHttp 依赖项

原文由 cesards 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1.4k
2 个回答

是的,它确实。

Retrofit 允许您设置自定义 HTTP 客户端,该客户端已根据您的需要进行配置。

至于自签名 SSL 证书, 这里 有讨论。该链接包含将自签名 SSL 添加到 Android 的 DefaultHttpClient 并将此客户端加载到 Retrofit 的代码示例。

如果您需要 OkHttpClient 接受自签名 SSL,则需要通过 setSslSocketFactory(SSLSocketFactory sslSocketFactory) 方法传递自定义 javax.net.ssl.SSLSocketFactory 实例。

获取套接字工厂的最简单方法是从 javax.net.ssl.SSLContext 获取一个,如此 讨论。

下面是配置 OkHttpClient 的示例:

 OkHttpClient client = new OkHttpClient();
KeyStore keyStore = readKeyStore(); //your method to obtain KeyStore
SSLContext sslContext = SSLContext.getInstance("SSL");
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(keyStore);
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyManagerFactory.init(keyStore, "keystore_pass".toCharArray());
sslContext.init(keyManagerFactory.getKeyManagers(),trustManagerFactory.getTrustManagers(), new SecureRandom());
client.setSslSocketFactory(sslContext.getSocketFactory());


okhttp3 的更新代码(使用构建器):

     OkHttpClient client = new OkHttpClient.Builder()
            .sslSocketFactory(sslContext.getSocketFactory())
            .build();


这里的 client 现在配置为使用来自你的 KeyStore 的证书。但是,它只会信任您的 KeyStore 中的证书,并且不会信任任何其他证书,即使您的系统默认信任它们。 (如果您的 KeyStore 中只有自签名证书,并尝试通过 HTTPS 连接到 Google 主页,您将获得 SSLHandshakeException )。

您可以从文件中获取 KeyStore 实例,如 文档 所示:

 KeyStore readKeyStore() {
    KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());

    // get user password and file input stream
    char[] password = getPassword();

    java.io.FileInputStream fis = null;
    try {
        fis = new java.io.FileInputStream("keyStoreName");
        ks.load(fis, password);
    } finally {
        if (fis != null) {
            fis.close();
        }
    }
    return ks;
}

如果你在 android 上,你可以把它放在 res/raw 文件夹中并从 Context 实例中获取它使用

fis = context.getResources().openRawResource(R.raw.your_keystore_filename);

有几个关于如何创建密钥库的讨论。例如 这里

原文由 Andrey Makarov 发布,翻译遵循 CC BY-SA 4.0 许可协议

另外需要注意的是,如果你在设备上预先安装了 CA,你可以使用 OKHttp 进行常规的 https 调用,而不需要特殊的 ssl hoops。关键是将网络安全配置添加到您的清单中。

我知道这样做的关键是我遇到了以下异常。

找不到证书路径的信任锚。

这是一篇来自谷歌的关于如何配置它的好文章。 https://developer.android.com/training/articles/security-config

这是我的 network_security_config.xml 的示例

<?xml version="1.0" encoding="UTF-8" ?>
<network-security-config>
    <base-config cleartextTrafficPermitted="false">
        <trust-anchors>
            <certificates src="user"/>
            <certificates src="system"/>
        </trust-anchors>
    </base-config>
</network-security-config>

原文由 Brian S 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题