В нашем приложении мы делаем HTTP-вызов для аутентификации через HTTPS.Я должен убедиться, что мы делаем все необходимые проверки, чтобы убедиться, что соединение безопасно.В качестве части этого я должен реализовать следующее:
- Убедитесь, что сертификат сервера аутентификации выпущен известным CA.
- Убедитесь, что имя хоста, присутствующее в сертификате сервера аутентификации, совпадаетимя хоста, которое мы используем для подключения к серверу авторизации.
У меня нет проблем с пунктом 1.
Для пункта 2 я пытаюсь использовать HostNameVerifier реализация.
Мой код на данный момент:
package com.company;
import sun.security.x509.X500Name;
import javax.net.ssl.*;
import java.net.URL;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
public class Main {
public static void main(String[] args) throws Exception {
URL endpoint = new URL("https://example.com");
HttpsURLConnection conn = (HttpsURLConnection) endpoint.openConnection();
conn.setHostnameVerifier(new MyHostNameVerifier());
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, new TrustManager[] {trustAll}, null);
conn.setSSLSocketFactory(sslContext.getSocketFactory());
System.out.println("HTTP Response: " + conn.getResponseCode());
}
public static final X509TrustManager trustAll = new X509TrustManager() {
@Override
public void checkClientTrusted(X509Certificate[] x509Certificates,
String s) throws CertificateException {
}
@Override
public void checkServerTrusted(X509Certificate[] x509Certificates,
String s) throws CertificateException {
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
};
public static class MyHostNameVerifier implements HostnameVerifier {
@Override
public boolean verify(String hostName, SSLSession sslSession) {
System.out.println("*** Validating host name for " + hostName);
return false;
}
}
}
Я ожидал, что MyHostNameVerifier#verify
всегда будет вызываться, и я могу сделать определенные проверки там.
Однако я заметил, что метод HostNameVerifier#verify
вызывается только в том случае, если я использовал IP-адрес сайта или только если имя хоста не совпадает с темой сертификата или каким-либо из альтернативных имен субъекта.
HostNameVerifier#verify
не вызывается в следующих случаях:
- Если сертификат сайта является подстановочным сертификатом и соответствует используемому имени хоста.
- Если сертификат сайта является сертификатом SANа если имя хостаЯ использую либо CN субъекта, либо указан как одно из значений альтернативного имени субъекта.
Например: в приведенном выше коде я пытаюсь подключиться к «example.com».
SSL-сертификат «example.com» выдается CN «www.example.org».
Однако «example.com» указан в «Subject Alternate Names» (SAN) сертификата.
Если я вместо этого использую IP-адрес «example.com», то вызывается мой верификатор имени хоста.
URL endpoint = new URL("https://93.184.216.34/");
Может ли кто-нибудь подтвердить мне, что Java внутренне обрабатывает сертификаты подстановочных знаков и проверки сертификатов SAN?Если да, тогда мне, возможно, не придется вносить какие-либо дополнительные изменения кода.