本文介绍了SSL证书固定无法在Android 9上正常工作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用下面的证书固定代码,该代码已经使用了一段时间(为简洁起见,已删除错误处理):

I'm using the following certificate pinning code which has worked for a while (error handling edited out for brevity's sake):

private static SSLContext _ssl_context = null;

public static SSLSocketFactory get_ssl_socket_factory(Context context)
{
    if (_ssl_context != null) {
        return _ssl_context.getSocketFactory();
    }

    KeyStore keystore = get_keystore(context);
    try
    {
        TrustManagerFactory tmf = TrustManagerFactory.getInstance("X509");
        tmf.init(keystore);
        _ssl_context = SSLContext.getInstance("TLS");
        _ssl_context.init(null, tmf.getTrustManagers(), null);
        return _ssl_context.getSocketFactory();
    }
    catch (GeneralSecurityException e) {
        // ...
    }
}

这是官方文档提供的代码.然后按如下方式使用SocketFactory:

This is more or less code provided by the official documentation. The SocketFactory is then used as follows:

if ("https".equals(target.getProtocol()) &&
    "example.com".equals(target.getHost()) &&
    huc instanceof HttpsURLConnection)
{
    ((HttpsURLConnection) huc).setSSLSocketFactory(
            SSLHelper.get_ssl_socket_factory(this));
}

当我在Android 8设备上运行此代码时,一切正常.但是,在我的Android 9模拟器上,会引发异常:

When I run this code on an Android 8 device, things work as expected. On my Android 9 emulator however, an exception is thrown:

E/App: https://example.com/page.html could not be retrieved! (Hostname example.com not verified:
            certificate: sha1/VYMjxowFaRuZpycEoz+srAuXzlU=
            subjectAltNames: [])
        javax.net.ssl.SSLPeerUnverifiedException: Hostname example.com not verified:
            certificate: sha1/VYMjxowFaRuZpycEoz+srAuXzlU=
            subjectAltNames: []
            at com.android.okhttp.internal.io.RealConnection.connectTls(RealConnection.java:201)
            at com.android.okhttp.internal.io.RealConnection.connectSocket(RealConnection.java:149)
            at com.android.okhttp.internal.io.RealConnection.connect(RealConnection.java:112)
            at com.android.okhttp.internal.http.StreamAllocation.findConnection(StreamAllocation.java:184)
            at com.android.okhttp.internal.http.StreamAllocation.findHealthyConnection(StreamAllocation.java:126)
            at com.android.okhttp.internal.http.StreamAllocation.newStream(StreamAllocation.java:95)
            at com.android.okhttp.internal.http.HttpEngine.connect(HttpEngine.java:281)
            at com.android.okhttp.internal.http.HttpEngine.sendRequest(HttpEngine.java:224)
            at com.android.okhttp.internal.huc.HttpURLConnectionImpl.execute(HttpURLConnectionImpl.java:461)
            at com.android.okhttp.internal.huc.HttpURLConnectionImpl.connect(HttpURLConnectionImpl.java:127)
            at com.android.okhttp.internal.huc.DelegatingHttpsURLConnection.connect(DelegatingHttpsURLConnection.java:89)
            at com.android.okhttp.internal.huc.HttpsURLConnectionImpl.connect(HttpsURLConnectionImpl.java:26)
            at ...

似乎Android 9中发生了一些变化,但是到目前为止,我还没有找到有关此行为的任何信息.我的想法如下:

It seems that something has changed in Android 9, but so far I haven't been able to find any information regarding this behavior. My ideas are the following:

  • 也许已不赞成使用这种方式进行证书固定
  • 也许Android 9将不再使用SHA1证书来验证域

还有其他想法吗?

推荐答案

我只是遇到了同样的问题.根据Android 9 Change-Log,对于没有SAN的证书,这是预期的:

I just had the same issue. According to the Android 9 Change-Log this is expected for certificates without SAN:

但是,RFC 2818中不推荐使用CN,因此,Android不再使用CN.要验证主机名,服务器必须出示具有匹配SAN的证书.不再信任不包含与主机名匹配的SAN的证书.

However, the fallback to the CN was deprecated in RFC 2818. For this reason, Android no longer falls back to using the CN. To verify a hostname, the server must present a certificate with a matching SAN. Certificates that don't contain a SAN matching the hostname are no longer trusted.

来源:使用证书进行主机名验证

这篇关于SSL证书固定无法在Android 9上正常工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

07-31 20:04