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

2022-08-31 12:00:45

我为一位拥有具有自签名 SSL 证书的服务器的客户工作。

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

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

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

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


答案 1

是的,确实如此。

改造允许您设置自定义 HTTP 客户端,该客户端根据您的需求进行配置。

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

如果需要接受自签名 SSL,则需要通过方法将其传递自定义实例。OkHttpClientjavax.net.ssl.SSLSocketFactorysetSslSocketFactory(SSLSocketFactory 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();

此处现在已配置为使用 .但是,它只会信任您的证书,而不会信任其他任何内容,即使您的系统默认信任它们也是如此。(如果您只有自签名证书,并尝试通过HTTPS连接到Google主页,您将获得)。clientKeyStoreKeyStoreKeyStoreSSLHandshakeException

您可以从文件中获取实例,如文档中所示: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/rawContext

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

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


答案 2

另一件需要注意的事情是,如果您在设备上预安装了CA,则可以使用OKHttp进行常规https调用,并且没有特殊的SSL箍。关键是将网络安全配置添加到清单中。

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

"未找到证书路径的信任锚。"

这是Google关于如何配置它的一篇好文章。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>

推荐