19 смертных грехов, угрожающих безопасности программ
Шрифт:
event.getPeerCertificates ;
В результате будет возвращен массив объектов типа javasecuritycert.Certi–ficate. Certificate – это базовый класс, фактический тип полученных объектов обычно представлен производным классом java.security.cert.X509Extension, хотя иногда встречаются и устаревшие сертификаты (типа java.security.cert.X509, которому наследует X509Extension).
Первым в массиве идет сертификат партнера, а за ним – сертификаты удостоверяющих центров по цепочке вплоть до корневого. При вызове этого метода Java API выполняет некоторые проверки сертификатов с целью убедиться в поддержке
try {
((X509Extension)(certificate[0])).verify(certificate[1].getPublicKey);
} catch (Exception e) {
/* Проверка сертификата завершилась неудачно. */
}
Отметим, что здесь не проверяется корректность даты каждого сертификата. Это можно было бы сделать так:
try {
((X509Extension)(certificate[0])).checkValidity;
} catch (Exception e) {
/* Проверка сертификата завершилась неудачно. */
}
В каркасе .NET имеются аналогичные средства:
X509Certificate2 cert = new X509Certificate2(@"c:\certs\server.cer");
X509Chain chain = new X509Chain;
chain.Build(cert);
if (chain.ChainStatus.Length > 0) {
// Были ошибки
}
Проверка имени хоста
Предпочтительный способ проверить имя хоста – воспользоваться полем dnsName из расширения subjectAltName, если оно имеется и заполнено. Но часто имя хоста записывается в поле DN. API для проверки этих полей варьируются в широких пределах.
В JavaJSSE в предположении, что мы имеем дело с сертификатом X509Exten–sion, можно следующим образом проверить значение subjectAltName, а в случае неудачи обратиться к полю DN:
private Boolean validateHost(X509Extension cert) {
String s = "";
String EXPECTED_HOST = "www.example.com";
try {
/* 2.5.29.17 – это OID, стандартное числовое представление имени
расширения */
s = new String(cert.getExtensions("2.5.29.17"));
if (s.equals(EXPECTED_HOST)) {
return true;
}
else { /* если расширение есть, но не соответствует
* ожидаемому значению, не будем проверять поле DN,
* которое НЕ ДОЛЖНО иметь другое значение. */
return false;
}
} catch (Exception e) {} /* Такого расширения нет, проверим DN */
if (cert.getSubjectDN.getName.equals(EXPECTED_HOST)) {
return true;
} else {
return false;
}
}
В каркасе .NET имя хоста проверяется автоматически при вызове метода SslStream. AuthenticateAsClient.
Проверка отзыва сертификата
Самым популярным способом проверки факта отзыва сертификата (если вообще можно говорить о популярности столь нечасто применяемой методики) по–прежнему остается сверка с CRL–списком. Следовало бы рекомендовать протокол OCSP, но УЦ не торопятся с его поддержкой. Компания VeriSign поддерживает
Но обратимся к CRL–спискам. Во–первых, для сверки вы должны иметь много CRL–списков. Необходимо узнать адрес точки распространения CRL, которая (если существует) может быть доступна по протоколам HTTP или LDAP. Иногда адрес указан в сертификате, а иногда – нет. В табл. 10.1 приведен список известных точек распространения CRL, работающих по протоколу HTTP. Можете использовать этот список в случае, когда адрес отсутствует в самом сертификате.
Во–вторых, нужно решить, как часто загружать CRL–списки. Обычно УЦ регулярно обновляют списки отозванных сертификатов, даже если никаких новых записей в них не появилось. Мы рекомендуем загружать новую версию с точно такой же периодичностью, не позже чем через 24 ч после обновления.
В–третьих, необходимо контролировать, что загруженный CRL–список действительно опубликован соответствующим УЦ (для этого нужно проверить цифровую подпись).
И наконец, проверяя каждый предъявленный сертификат, следует убедиться, что ни один из сертификатов в цепочке доверия не внесен в имеющиеся CRL–списки. Если какой–то сертификат отозван, то соединение устанавливать нельзя.
В CRL заносятся просто идентификаторы сертификатов. Чтобы сверить сертификат с CRL–списком, нужно извлечь поле ID и посмотреть, есть ли оно в этом списке.
Таблица 10.1. Адреса точек распространения CRL–списков для популярных УЦ
Дополнительные защитные меры
В идеале, помимо описанных в этой главе проверок, надо бы проверять и другие критические расширения сертификата Х.509. При этом вы должны ясно понимать смысл всех критических расширений. Тогда вы не спутаете, например, сертификат для подписания кода с SSL–сертификатом. Вообще говоря, такие проверки могут представлять интерес, но обычно они не настолько важны, как может показаться.
Чтобы снизить риск кражи верительных грамот, после чего сертификат придется отозвать, можно рассмотреть возможность применения специального оборудования для ускорения работы с SSL. Большинство таких продуктов хранят секретные данные в аппаратуре и не показывают их компьютеру ни при каких обстоятельствах. Таким образом, хакер, взломавший вашу машину, ничего не добьется. Некоторые устройства оборудованы также средствами против физического вмешательства, так что даже физическая атака становится затруднительной.
И наконец, если вас пугает сложность дотошной проверки SSL–сертификатов, а ваше приложение общается только с небольшим числом серверов, то можете зашить в код все действительные сертификаты и сличать все байты. Такой подход на основе списков допустимых сертификатов можно дополнить собственной схемой PKI, но в долгосрочной перспективе это окажется более дорогостоящим и трудоемким делом, чем реализация корректной проверки с самого начала.
Другие ресурсы