Написание SSL Checker с использованием Java
Кто-нибудь знает какие-нибудь хорошие учебники, сайты и / или книги по написанию проверки SSL на Java? Я пытаюсь сделать то, что можно найти здесь: http://www.sslshopper.com/ssl-checker.html. Я не пытаюсь создать самоподписанный сертификат или использовать хранилище ключей. Я хочу иметь возможность зайти на любой сайт, определить, существует ли действительный сертификат SSL, определить, совпадает ли имя хоста в сертификате с введенным именем, и определить, когда истекает срок действия этого сертификата. Я погуглил эту тему, но "Как создать покупателя SSL с помощью Java" ничего мне не дало, а мои другие поиски только принесли мне ссылки на то, как создать самоподписанный сертификат. Любая помощь будет принята с благодарностью.
2 ответа
Чтобы получить сертификат сервера, прежде всего, чтобы выполнить проверку вручную, независимо от того, действителен ли он или нет, проще всего подключиться через SSLSocket
после отключения любой проверки сертификата.
Создать SSLContext
что пропускает что-либо через:
SSLContext sslContext = SSLContext.getInstance("TLS");
X509TrustManager passthroughTrustManager = new X509TrustManager() {
@Override
public void checkClientTrusted(X509Certificate[] chain,
String authType) throws CertificateException {
}
@Override
public void checkServerTrusted(X509Certificate[] chain,
String authType) throws CertificateException {
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return null;
}
};
sslContext.init(null, new TrustManager[] { passthroughTrustManager },
null);
(Примечание: для людей, которые ищут способ использовать тестовые сертификаты для внутреннего использования, я бы рекомендовал создавать свой собственный тестовый центр сертификации, а не отключать проверки, на тот случай, если эти фиктивные проверки останутся в рабочем коде по ошибке, а также потому, что тесты более реалистичные.)
Создайте сокет, подключите и запустите рукопожатие явно (поскольку вы не собираетесь читать его):
SSLSocketFactory ssf = sslContext.getSocketFactory();
SSLSocket socket = (SSLSocket) ssf.createSocket(
"the.host.name", 443);
socket.startHandshake();
Получить цепочку сертификатов сверстников. Первый элемент - это действительный сертификат сервера.
X509Certificate[] peerCertificates = (X509Certificate[]) socket
.getSession().getPeerCertificates();
Если вы хотите проверить соответствие с доверенными якорями по умолчанию (доверенными сертификатами CA по умолчанию), создайте X509TrustManager
на основе значений по умолчанию (это эффективно то, что passthroughTrustManager
выше отключен):
// By default on Oracle JRE, algorithm is PKIX
TrustManagerFactory tmf = TrustManagerFactory
.getInstance(TrustManagerFactory.getDefaultAlgorithm());
// 'null' will initialise the tmf with the default CA certs installed
// with the JRE.
tmf.init((KeyStore) null);
X509TrustManager tm = (X509TrustManager) tmf.getTrustManagers()[0];
Теперь проверьте, действителен ли сертификат в данный момент, проверен ли он на доверенном якоре и имеет ли он правильные расширения в соответствии с RFC 3280.
try {
// Assuming RSA key here.
tm.checkServerTrusted(peerCertificates, "RSA");
} catch (CertificateException e) {
// Here you may check which subclass of CertificateException to know what the error is.
}
Все вышеперечисленное использует JSSE API.
В качестве альтернативы, если вы хотите углубиться в детали PKIX, вы можете использовать Java Certification Path API (который используется JSSE).
(Если для начала вам нужны только действительные сертификаты, просто используйте SSLContext sslContext = SSLContext.getDefault()
в начале создайте сокет и сделайте рукопожатие.)
Чтобы получить сертификат сервера напрямую, вы можете использовать это:
X509Certificate serverCert = peerCertificates[0];
X509Certificate
имеет ряд методов, касающихся дат и различных расширений. Например:
Date expirationDate = serverCert.getNotAfter();
Проверка имени хоста должна соответствовать RFC 6125 (или хотя бы RFC 2818). Короче говоря, проверьте, является ли имя хоста, к которому вы хотите подключиться, одной из DNS-записей Subject Alternative Names (SAN). В противном случае вернитесь к проверке, находится ли имя хоста в CN RDN вашего сертификата (для этого вам нужно разделить Subject DN на RDN). Вас также может заинтересовать это обсуждение (в конкретном случае использования IP-адресов).
Все зависит от того, сколько "ручной" проверки вы хотите сделать. Есть ряд спецификаций для чтения (RFC 5280/RFC 3280 и RFC 6125/RFC 2818 по крайней мере), в дополнение к документации API.
Этот вопрос на Security.SE также должен представлять интерес:
Что вы можете сделать, так это реализовать свой собственный инструмент проверки, например, в http://Apache%20Http%20Client
Вы должны инициализировать контекст SSL и переопределить TrustManagers
сделать любую проверку, которую вы хотите.
Проверка имени хоста может выполняться библиотекой автоматически.
Например, следующее настроит обработку сокета SSL для выдачи исключения, если имя хоста не соответствует информации сертификата:
SSLSocketFactory sf = new SSLSocketFactory(
SSLContext.getInstance("TLS"),
SSLSocketFactory.STRICT_HOSTNAME_VERIFIER);