Android изменил конфигурацию SSL в API 24?

Когда мой проект 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)

Решение Вопроса

Установленные пользователем сертификаты через приложение «Настройки» по умолчанию не включены в Android 7.0, если вашtargetSdkVersion 24+:

По умолчанию защищенные соединения (например, TLS, HTTPS) из всех приложений доверяют предварительно установленным системным ЦС, а приложения, ориентированные на уровень API 23 (Android M) и ниже, также доверяют добавленному хранилищу ЦС по умолчанию.

(отдокументы по настройке безопасности сети)

Чтобы обойти это, вам нужно определитьнастройка безопасности сети 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>

Затем укажите на этот ресурс XML из вашегоandroid:networkSecurityConfig атрибут в вашем<application> элемент в вашем манифесте.

Как правило, Android 7.0 маршрутизирует HTTPS через подсистему настройки безопасности сети (android.security.net.config.RootTrustManager и род от вашего следа стека). Вполне возможно, что здесь представлены другие проблемы совместимости, связанные сtargetSdkVersion, Таким образом, если отсутствие пользовательских сертификатов не является вашей проблемой, и вы можете создать пример проекта, который воспроизводит проблему,подать проблему, Так как я поддерживаюбэкпорт этого материалаМне было бы интересно узнать о любых ошибках. :-)

 CommonsWare20 июл. 2017 г., 18:51
@Andigor: если вы настраиваете самозаверяющий сертификат через конфигурацию безопасности сети, вам не нужноSSLContext совсем. Подсистема конфигурации безопасности сети обрабатывает все это для вас. Просто определите ресурс XML, добавьте его в манифест черезandroid:networkSecurityConfigи все готово.
 hmac13 мар. 2018 г., 17:59
обратите внимание, что вы можете использовать<debug-overrides> скорее, чем<base-config>
 andigor20 июл. 2017 г., 17:42
Нужно ли писать код для Andorid 7, чтобы начать использовать «подсистему настройки безопасности сети»?
 CommonsWare04 авг. 2016 г., 17:04
@ НатанХ: Готово.
 CommonsWare04 авг. 2016 г., 16:51
@NathanH: Это относится к ресурсу XML, где вы предоставляетенастройка безопасности сети, Что-токак это, но где вы включаете<certificates src="user"/> и бросьте<certificates src="@raw/extracas"/> (которого у вас не будет) должно работать. Затем добавьтеandroid:networkSecurityConfig в<application>, указывая на этот ресурс XML.
 Nathan H04 авг. 2016 г., 17:01
Работает! Не могли бы вы добавить этот обходной путь к своему ответу?
 CommonsWare20 июл. 2017 г., 17:48
@Andigor: в идеале да. На практике это вопрос для тех, кто поддерживает ваш сервер. Например, решение о том, как реализовать закрепление сертификатов, является их решением так же, как и разработчиками приложений для Android.
 CommonsWare25 дек. 2016 г., 01:13
@abhijitcaps: поговорите с сопровождающими сервера. Если у вас есть дополнительные проблемы в этой области, пожалуйста, подумайте над тем, чтобы задать отдельный вопрос о переполнении стека, где вы предоставите более подробную информацию о проблемах, с которыми вы столкнулись.
 Nathan H04 авг. 2016 г., 16:33
Да, я нашел эту информацию, когда вы ее опубликовали. Действительно, кажется, мой сертификат находится в доверительном управлении, установленном пользователем.
 abhijitcaps25 дек. 2016 г., 01:04
Как мне найти значение для доверия якоря
 Nathan H04 авг. 2016 г., 16:46
Где я должен поместить эту строку XML, которую вы предоставили? Я не слишком беспокоюсь о реальной безопасности, это для теста
 andigor20 июл. 2017 г., 18:47
Спасибо за ответ. Я не очень знаком с этой темой. Так что вопрос прост. У меня есть код, который импортирует самозаверяющий сертификат в пользовательский менеджер доверия и затем передает его в контекст SSLContext. Это перестало работать на Android 7. Я вижу, что есть новый способ доверять сертификатам с использованием конфигурации XML. Итак, что мне теперь перейти к SSLContext, если я использую упомянутую новую схему?
 CommonsWare04 авг. 2016 г., 16:37
@NathanH: Ваше приложение может использовать установленные пользователем сертификаты через<certificates src="user"/>, Если возможно, сделайте что-нибудь еще. Установленные пользователем сертификаты распространяются на все устройства, что не очень хорошо. Вы должны быть в состоянии настроитьнастройка безопасности сети запекает нужный сертификат в ваше приложение.

Ваш ответ на вопрос