【问题标题】:SSL Certificate Pinning not working anymore on Android 9SSL 证书固定在 Android 9 上不再工作
【发布时间】:2019-02-24 20:40:58
【问题描述】:

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

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 证书验证域

还有其他想法吗?

【问题讨论】:

  • 在你的情况下,根据堆栈跟踪,它是未经验证的主机名。 example.com 与 domain.com。我有类似的问题。当使用通配符颁发证书时,固定不起作用。比如cn=*.domain.com。所以 my.domain.com 不被接受。
  • 对不起,“domain.com”混淆了,它是根据 SO 指南编辑的,有一个被遗漏了。应用程序中的实际域在这两种情况下都完全匹配,并且不是通配符。
  • 我必须使用主题替代名称(如 SAN DNS:*.domain.com)创建新证书,并且它可以工作。看来android 9对CN验证设置了一些限制
  • 您能否说明需要添加为 SAN 的内容?

标签: android ssl certificate-pinning


【解决方案1】:

要验证主机名,服务器必须提供具有匹配 SAN 的证书。不包含与主机名匹配的 SAN 的证书不再受信任。

我的查询是证书是否是像 *.mydomain.com 这样的域的通配符 online.mydomain.com 。 SAN *.mydomain.com 会起作用还是不再支持通配符?

【讨论】:

    【解决方案2】:

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

    RFC 2818 描述了将域名与证书匹配的两种方法——使用 subjectAltName (SAN) 扩展中的可用名称,或者在没有 SAN 扩展的情况下,使用 commonName (CN)。

    但是,在 RFC 2818 中已弃用回退到 CN。因此,Android 不再回退到使用 CN。要验证主机名,服务器必须提供具有匹配 SAN 的证书。不包含与主机名匹配的 SAN 的证书不再受信任。

    来源: Hostname verification using a certificate

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-09-17
      • 2021-12-20
      • 1970-01-01
      • 2018-03-04
      • 1970-01-01
      • 2017-11-21
      • 1970-01-01
      相关资源
      最近更新 更多