Закрепление открытого ключа с помощью X509TrustManagerExtensions checkServerTrusted
Закрепление открытого ключа для соединения HTTPS TLS.
Существует проблема с Android API, ниже 17, которая позволяет MITM (Человек в середине) атаки в случае закрепления открытого ключа. Это было объяснено в ссылке ниже.
https://www.cigital.com/blog/ineffective-certificate-pinning-implementations/
Таким образом, в Android минимум sdk ниже 17, то есть ниже Android версии 4.2, мы должны инициализировать X509TrustManager с Android Keystore, в котором есть только корневые сертификаты сервера (вместо хранилища ключей по умолчанию; в нем будут установлены все сертификаты на устройстве). Это помогает очистить листовые сертификаты, полученные от сервера, перед выполнением закрепления открытого ключа.
Начиная с Android API 17 и выше, Android представила X509TrustManagerExtensions, которая выполняет эту корневую очистку на уровне ОС.
https://developer.android.com/reference/android/net/http/X509TrustManagerExtensions.html
Мой вопрос:
Я был бы рад, если бы кто-нибудь мог предоставить пример того, как реализовать следующий метод, предоставляемый X509TrustManagerExtensions для очистки корня.
List<X509Certificate> checkServerTrusted (X509Certificate[] chain,
String authType,
String host)
Меня смущает следующее.
host
; это должен быть URL домена? с https или без? или это должен быть полный URL (домен + относительный путь)Как создать мгновение
X509TrustManagerExtensions
? Конструктор для X509TrustManagerExtensions принимаетX509TrustManager
в качестве ввода. Создаем ли мы этот X509TrustManager с хранилищем ключей по умолчанию для Android?
Фрагмент кода (не работает):
TrustManagerFactory tmf = TrustManagerFactory.getInstance("X509");
tmf.init(KeyStore.getInstance(KeyStore.getDefaultType()));
for (TrustManager trustManager : tmf.getTrustManagers()) {
X509TrustManagerExtensions tme = new X509TrustManagerExtensions((X509TrustManager) trustManager);
tme.checkServerTrusted(chain, authType, <<String https://www.example.com>>);
}
Исключение: не найдена доверенная привязка для пути сертификации
Возможный риск безопасности: использование KeyStore.getDefaultType()
Любая помощь будет принята с благодарностью.
1 ответ
Во-первых, вам нужно завладеть доверительным менеджером, используя TrustManagerFactory
, При инициализации этого вы передаете нуль для того, чтобы использовать по умолчанию Keystore
и он вернет доверенные менеджеры по умолчанию. С этим вы можете создать X509TrustManagerExtensions
используя первый X509TrustManager
,
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(
TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init((KeyStore) null);
// Find first X509TrustManager in the TrustManagerFactory
X509TrustManager x509TrustManager = null;
for (TrustManager trustManager : trustManagerFactory.getTrustManagers()) {
if (trustManager instanceof X509TrustManager) {
x509TrustManager = (X509TrustManager) trustManager;
break;
}
}
X509TrustManagerExtensions x509TrustManagerExtensions =
new X509TrustManagerExtensions(trustManager());
Затем для выполнения этого хоста я успешно использовал только часть домена:
List<X509Certificate> trustedCerts = x509TrustManagerExtensions
.checkServerTrusted(untrustedCerts, "RSA", "appmattus.com");
Для тех, кто использует HttpUrlConnection
Ненадежные сертификаты определяются с помощью:
Certificate[] serverCerts = ((HttpsUrlConnection)conn).getServerCertificates();
X509Certificate[] untrustedCerts = Arrays.copyOf(serverCerts,
serverCerts.length,
X509Certificate[].class);
Если вы используете OkHttp, вы можете просто использовать встроенный CertificatePinner, который с тех пор был обновлен, чтобы исправить проблемы, упомянутые в этой статье.