Дэвид Лебланк - 19 смертных грехов, угрожающих безопасности программ
Другую возможность предоставляет протокол онлайнового запроса статуса сертификата (OCSP – Online Certificate Status Protocol). Его назначение – уменьшить промежуток времени, в течение которого сервер уязвим, за счет внедрения онлайновой службы, у которой можно запросить статус сертификата. Но, как и в случае CRL, этот протокол не слишком хорошо поддерживается. (Вопреки требованиям стандарта IETF многие УЦ и библиотеки для работы с SSL не поддерживают его вовсе, а в тех, которые поддерживают, этот режим, скорее всего, по умолчанию отключен.) Кроме того, есть проблемы, присущие только OCSP. Самая очевидная из них – в том, что необходим доступ по сети к службе, отвечающей на запросы. Поэтому при реализации OCSP нужно считать сертификат недействительным в случае недоступности службы или хотя бы реализовать второй эшелон обороны: загружать и проверять CRL, причем отказываться принимать сертификат, если CRL последний раз обновлялся слишком давно.
Основные проблемы SSL мы описали, но есть еще кое–что, заслуживающее хотя бы краткого упоминания. Во–первых, в предыдущих версиях SSL были просчеты, как серьезные, так и не очень. Мы рекомендуем пользоваться последней версией TLS, а не устаревшими. Особенно это относится к версиям SSLv2 и РСТ. Это может оказаться нелегко, поскольку библиотеки по умолчанию часто в ходе установления сеанса соглашаются на любую версию протокола, поддерживаемую другой стороной. Не применяйте шифры, не обладающие достаточной криптографической стойкостью. Особенно избегайте семейства шифров RC4. Этот шифр известен своим быстродействием, поэтому к нему часто прибегают в надежде повысить производительность приложения, хотя при использовании SSL этот выигрыш не так заметен. Но RC4 криптографически нестоек, есть данные в пользу того, что его можно вскрыть при наличии достаточно большого объема зашифрованных данных, даже если следовать всем рекомендациям. А вообще–то узкое место для большинства приложений – это операции с открытым ключом во время начальной аутентификации, а не последующее шифрование (если, конечно, вы не пользуетесь шифром 3DES).
Родственные грехи
В этой главе мы говорим главным образом об аутентификации сервера клиентом, хотя в общем случае и сервер должен аутентифицировать клиента. Обычно клиент должен сначала аутентифицировать сервера. Убедившись, что общается с нужным партнером по защищенному каналу, клиент посылает свои верительные грамоты (хотя SSL предлагает и другие механизмы, на выбор). Протоколы аутентификации клиента, особенно по паролю, сопряжены с целым рядом рисков, как вы увидите в грехе 11.
По сути дела наша основная трудность – это частный случай гораздо более широкой проблемы, заключающейся в том, что две стороны хотят выработать общий криптографический ключ, но делают это небезопасным способом. Эта проблема будет рассмотрена в грехе 17.
Помимо того, некоторые библиотеки повышают риск, выбирая неудачные ключи. Причина – в использовании случайных чисел недостаточно высокого качества. Это тема греха 18.
Где искать ошибку
Есть несколько мест, на которые следует обратить внимание, и прежде всего это недостаточно тщательная проверка подлинности сертификата. Ищите места, где:
□ используется SSL или TLS;
□ не используется HTTPS;
□ ни библиотека, ни приложение не проверяют, что сертификат выпущен известным УЦ;
□ ни библиотека, ни приложение не контролируют важные поля в сертификате сервера.
Если приложение не удовлетворяет этим требованиям, то проверять, отозван ли сертификат, обычно не имеет смысла, так как есть проблемы, куда более серьезные, чем похищенные верительные грамоты.
Если же с указанными выше задачами приложение справляется, то следует обратить внимание на вопросы, связанные с CRL:
□ используется SSL или TLS;
□ не проверяется, был ли похищен закрытый ключ сервера и не отозван ли сертификат.
Выявление ошибки на этапе анализа кода
Прежде всего найдите все точки входа в приложение из сети. Для каждой точки входа определите, используется ли протокол SSL. API сильно зависит от библиотеки и языка, но поиска по словам «SSL» и «TLS» без учета регистра обычно хватает. Если вы пользуетесь старыми библиотеками Windows, ищите слово «РСТ» (Private Communication Technology – технология защищенной связи), это устаревшая версия предшественника SSLv3, разработанная Microsoft. Если некоторая точка входа не защищена SSL, может возникнуть серьезная проблема!
Остальные обсуждаемые в этой главе вопросы в большей степени связаны с кодом клиента, так как сервер часто аутентифицирует клиента по паролю или с помощью какого–то другого механизма. Но если используются клиентские сертификаты, то следует применять ту же методологию анализа и к коду сервера.
Для каждой точки входа, защищенной SSL, проверьте, сравнивается ли сертификат со списком известных хороших сертификатов (список разрешенных). В этом случае программа обычно не обращается к коммерческой инфраструктуре PKI, а реализует собственные средства управления сертификатами.
Если сертификат находится в списке допустимых, то все равно остается риск, что он отозван. Не исключено также, что сам этот список формируется небезопасным образом. Так или иначе, проверку следует проводить до начала обмена данными по установленному соединению.
Если программа не обращается к списку допустимых сертификатов, проверьте, выполнены ли все перечисленные ниже проверки:
□ сертификат подписан известным УЦ или имеется цепочка подписей, ведущая к известному УЦ;
□ срок действия сертификата еще не истек;
□ имя хоста сравнивается со значением в соответствующем подполе хотя бы одного из двух полей: DN или subjectAltName (последнее появилось в версии спецификации Х.509 v3);
□ неудачное завершение любой из этих проверок программа рассматривает как ошибку аутентификации и отказывается устанавливать соединение.
Во многих языках программирования для решения этой задачи приходится глубоко забираться в документацию или даже в сам код. Например, может ветретиться такой код на языке Python, в котором используется стандартный модуль «socket», включенный в Python 2.4:
...import socket
s = socket.socket()
s.connect(('www.example.org', 123))
ssl = socket.ssl(s)
Совершенно не ясно, какие именно проверки библиотека SSL выполняет по умолчанию. В случае Python ответ таков: согласно документации, библиотека не проверяет абсолютно ничего. В других языках могут проверяться срок действия и цепочка доверия, но тогда вы должны быть уверены, что имеется приемлемый список УЦ, и предпринять какие–то действия, если это не так.
Анализируя, насколько правильно реализована работа с отозванными сертификатами, посмотрите, используются ли вообще CRL–списки или протокол OCSP. И в этом отношении API сильно различаются, поэтому лучше изучить тот API, который применен в конкретной программе; поиска по словам «CRL» или «OCSP» без учета регистра обычно достаточно.
В случае, когда используются один или оба этих механизма, нужно обращать внимание на следующие вопросы:
□ производится ли проверка до отправки данных;
□ что происходит, если проверка завершается неудачно;
□ как часто загружаются CRL–списки;
□ проверяются ли сами CRL (особенно если они были загружены по обычному протоколу HTTP или LDAP).
Ищите код, который «заглядывает внутрь» сертификата в поисках некоторых деталей, например, значения поля DN, но не выполняет нужных криптографических операций. Так, следующий фрагмент греховен, поскольку проверяет лишь, что в сертификате есть текст «CN=www. example. сот», но ведь кто угодно мог выпустить для себя сертификат с таким именем:
...X509Certificate cert = new X509Certificate();
if (cert.Subject == "CN=www.example.com") {
// Ура, мы общаемся с example.com!
}
Тестирование
В настоящее время имеется несколько программ, которые автоматизируют атаку с «человеком посередине» против HTTPS. В частности, к ним относятся dsniff и ethercap. Впрочем, они работают только против HTTPS, поэтому при использовании против совместимого с HTTPS приложения должны отображать какое–нибудь окно или иным способом оповещать об ошибке, поскольку в противном случае под угрозой может оказаться вся инфраструктура приложения.
К сожалению, по–настоящему стабильные инструменты для автоматизации атак с «человеком посередине» общего назначения против SSL–приложений существуют только в хакерском подполье. Если бы в вашем распоряжении был такой инструмент, то вы могли бы дать ему действительный сертификат, подписанный известным УЦ, например VeriSign, и посмотреть, сумеет ли он расшифровать передаваемые по каналу данные. Если да, значит, исчерпывающая проверка подлинности сертификата не произведена.
Чтобы протестировать, как проверяются отозванные сертификаты по CRL–спискам и OSCP, можно просто проанализировать весь исходящий от приложения трафик за достаточно длительный период времени, сравнивая протоколы и адреса получателей с известными значениями. Если проверка по OSCP производится, то на каждую аутентификацию должен приходиться один запрос по этому протоколу. Если ведется проверка по CRL–спискам и она правильно реализована, то списки должны загружаться периодически, скажем, раз в неделю. Поэтому не удивляйтесь, если в коде проверка по CRL–списку присутствует, а в реальном трафике ее следов не видно. Очень может статься, что список уже был загружен и сохранен на локальном компьютере, чтобы избежать лишнего запроса.