安卓在API 24中是否改变了SSL配置?

5

当我的Android 23项目尝试通过HTTPS连接到我的服务器时,一切正常。

如果我将目标SDK切换到24,我会收到以下错误:

 javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
     at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:361)
     at android.net.SSLCertificateSocketFactory.verifyHostname(SSLCertificateSocketFactory.java:198)
     at android.net.SSLCertificateSocketFactory.createSocket(SSLCertificateSocketFactory.java:443)
     at org.apache.http.conn.ssl.SSLSocketFactory.createSocket(SSLSocketFactory.java:394)
     at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:170)
     at org.apache.http.impl.conn.AbstractPoolEntry.open(AbstractPoolEntry.java:169)
     at org.apache.http.impl.conn.AbstractPooledConnAdapter.open(AbstractPooledConnAdapter.java:124)
     at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:366)
     at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:560)
     at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:492)
     at com.worklight.wlclient.WLRequestSender.run(WLRequestSender.java:47)
     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133)
     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607)
     at java.lang.Thread.run(Thread.java:761)
 Caused by: java.security.cert.CertificateException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
     at com.android.org.conscrypt.TrustManagerImpl.verifyChain(TrustManagerImpl.java:563)
     at com.android.org.conscrypt.TrustManagerImpl.checkTrustedRecursive(TrustManagerImpl.java:444)
     at com.android.org.conscrypt.TrustManagerImpl.checkTrustedRecursive(TrustManagerImpl.java:508)
     at com.android.org.conscrypt.TrustManagerImpl.checkTrustedRecursive(TrustManagerImpl.java:508)
     at com.android.org.conscrypt.TrustManagerImpl.checkTrusted(TrustManagerImpl.java:401)
     at com.android.org.conscrypt.TrustManagerImpl.checkTrusted(TrustManagerImpl.java:375)
     at com.android.org.conscrypt.TrustManagerImpl.getTrustedChainForServer(TrustManagerImpl.java:304)
     at android.security.net.config.NetworkSecurityTrustManager.checkServerTrusted(NetworkSecurityTrustManager.java:94)
     at android.security.net.config.RootTrustManager.checkServerTrusted(RootTrustManager.java:88)
     at com.android.org.conscrypt.Platform.checkServerTrusted(Platform.java:178)
     at com.android.org.conscrypt.OpenSSLSocketImpl.verifyCertificateChain(OpenSSLSocketImpl.java:596)
     at com.android.org.conscrypt.NativeCrypto.SSL_do_handshake(Native Method)
     at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:357)
    ... 13 more
 Caused by: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.

切换回23版本后,它又可以工作了。24版本有关证书的最低要求是否发生了变化?

1个回答

12

如果您的targetSdkVersion是24+,则通过设置应用程序安装的用户证书在Android 7.0上默认不会被合并:

默认情况下,所有应用程序的安全连接(例如TLS、HTTPS)都信任预安装的系统CA。而目标API级别为23(Android M)及以下的应用程序也默认信任用户添加的CA存储。

(来自网络安全配置文档

为了解决这个问题,您需要定义一个网络安全配置XML资源:

<?xml version="1.0" encoding="utf-8"?>

<network-security-config>
    <base-config>
        <trust-anchors>
            <certificates src="system"/>
            <certificates src="user"/>
        </trust-anchors>
    </base-config>
</network-security-config>
然后,在您的清单文件的application元素中,通过您的android:networkSecurityConfig属性指向该XML资源。
通常情况下,Android 7.0通过网络安全配置子系统 (android.security.net.config.RootTrustManager等)路由HTTPS。这里可能存在其他与targetSdkVersion相关的兼容性问题。因此,如果缺少用户证书并不是您的问题,并且您可以创建一个重现此问题的示例项目,请提交问题。由于我维护这些内容的后移植版本,所以我很想知道是否存在任何错误。 :-)

是的,我在您发布此信息后找到了该信息。实际上,我的证书在用户安装的信任中。 - Nathan H
在开始使用“网络安全配置子系统”之前,是否需要编写适用于Android 7的任何代码? - andigor
@Andigor:理想情况下是这样的。但实际上,这是你的服务器维护人员需要考虑的问题。例如,决定如何实现证书固定,既是安卓应用程序开发者的决策,也是服务器维护人员的决策。 - CommonsWare
谢谢您的回答。我对这个话题不是很熟悉,所以问题很简单。我有一段代码,它将自签名证书导入到自定义信任管理器中,然后将其传递给SSLContext上下文。在Android 7上,这种方法停止工作了。我看到有一种新的方式可以使用XML配置来信任证书。那么,如果我使用这种新的方案,我现在应该传递什么给SSLContext呢? - andigor
@Andigor:如果您通过网络安全配置来配置自签名证书,则根本不需要SSLContext。网络安全配置子系统会为您处理所有这些内容。只需定义XML资源,通过android:networkSecurityConfig将其添加到清单中,就完成了。 - CommonsWare
显示剩余7条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接