android - SSL 证书固定在 Android 9 上不再有效

标签 android ssl certificate-pinning

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

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) {
        // ...
    }
}

这或多或少是由 official documentation 提供的代码.然后按如下方式使用 SocketFactory:

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 模拟器上,抛出了一个异常:

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 中发生了一些变化,但到目前为止我还没有找到有关此行为的任何信息。我的想法如下:

  • 也许这种证书固定方式已经被弃用了
  • 也许 Android 9 将不再使用 SHA1 证书验证域

还有其他想法吗?

最佳答案

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

RFC 2818 describes two methods to match a domain name against a certificate—using the available names within the subjectAltName (SAN) extension, or in the absence of a SAN extension, falling back to the commonName (CN).

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.

来源: Hostname verification using a certificate

关于android - SSL 证书固定在 Android 9 上不再有效,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52426755/

相关文章:

php - 如何使用 laravel 4 邮件方法设置 hotmail?

android - Android Webview 中的证书固定

ssl - ChromeDriver 仅打开具有有效 SSL 证书的网站

ssl - 指向 CNAME 到 openshift 抛出证书问题

android - Firebase 迁移到 androidX 时出现问题

java - 如何制作无法编辑的EditText?

android - 避免禁用证书固定 Android

swift - alamofire 中的证书固定是错误的

android - 如何在不同的 Activity 中接收 CameraActivities 结果(即不在启动 Activity 中)?

android - 使用最新的Gradle版本3.2.1时找不到源Java类