19 смертных грехов, угрожающих безопасности программ
Шрифт:
Ах, если бы таким образом можно было решить проблему!
Представьте, что в «середине» протокола аутентификации находится противник, и он не делает ничего, кроме подслушивания. Предположим, что противник не знает пароля и не получает никакой информации о нем из протокола (быть может, мы применяем схему с одноразовым паролем, например S/KEY). Что доказывает протокол аутентификации? Лишь тот факт, что никто не пытался изменить сообщения протокола (то есть сообщения аутентичны). Даже если противник все подслушал, «аутентификация» состоялась.
А что осталось недоказанным? Что аутентичными были сообщения, передаваемые в ходе исполнения протокола обмена ключами!
Чтобы организовать защищенный сеанс, обе стороны обычно должны удостовериться в «личности» собеседника (хотя в некоторых случаях одна из сторон может быть анонимной). Личность должна быть уже удостоверена к моменту начала исполнения протокола обмена ключами. При этом каждое последующее сообщение посылается с ключом (требование аутентичности сохраняется на все время сеанса, хотя часто мы называем это целостностью сообщений).
Почти никогда не имеет смысла выполнять обмен ключами без аутентификации. Поэтому все современные протоколы аутентификации, предназначенные для использования в сети, одновременно являются протоколами обмена ключами. И никто не конструирует автономный протокол обмена ключами, поскольку аутентификация – это основополагающее требование.
Родственные грехи
Мы взяли для примера протокол Диффи–Хеллмана, но та же проблема присуща и SSL/TLS, поскольку разработчики плохо понимают, что необходимо для адекватной аутентификации. Коль скоро процедуру аутентификации можно скомпрометировать, открывается возможность для атаки с «человеком посередине». Тема аутентификации в применении к протоколу SSL рассматривается в грехе 10.
Отметим еще, что люди, попавшиеся на этой ошибке, обычно строят собственные криптосистемы, сознательно или нет. Надежно защитить трафик при этом, скорее всего, не удастся (см. грех 8).
Где искать ошибку
Согрешить можно в любом приложении, которое выполняет аутентификацию по сети в ситуации, когда для этого требуется установить соединение, защищенное криптографическими методами. Фундаментальная проблема в том, что автор не осознает, что соединение недостаточно аутентифицировано (а иногда не аутентифицировано вовсе).
Выявление ошибки на этапе анализа кода
Вот как мы предлагаем искать признаки этого греха в программе:
1. Выявите те точки сетевых коммуникаций, где защита трафика обязательна (любой вид аутентификации и последующего обеспечения целостности сообщений, а также конфиденциальности, если это существенно для приложения).
2. Если защиты нет, это, очевидно, плохо.
3. Для каждой точки определите, используется ли при организации сеанса какой–нибудь протокол аутентификации. Плохо, если нет.
4. Проверьте, приводит ли протокол аутентификации к выработке ключа. Для этого нужно изучить выходную информацию протокола. Если не приводит, убедитесь, что протокол аутентифицирует данные, выработанные в ходе обмена ключами, и проверяет «личности» сторон способом, не поддающимся подделке. К сожалению, для обычного разработчика это может оказаться трудной задачей, лучше пригласить профессионального криптографа.
5. Если выработан ключ, проверьте, используется ли он для последующей защиты канала. Если нет, создается угроза локальной атаки с перехватом
6. Убедитесь, что аутентификационные сообщения нельзя подделать. В частности, если для аутентификации применяется цифровая подпись на открытом ключе, проверьте, можно ли доверять открытому ключу другой стороны. Обычно для этого нужно либо свериться со статическим списком известных сертификатов, либо воспользоваться инфраструкторой открытых ключей (PKI), контролируя попутно все относящиеся к делу поля сертификата. Подробнее см. грех 10.
7. Если процедура аутентификации может быть атакована, проверьте, относится ли это только к первой успешной попытке входа в систему или также и ко всем последующим. Если начальная аутентификация может быть атакована, а последующие – нет, то аудитор должен признать, что оснований для беспокойства куда меньше, чем в случае, когда угрозе атаки с «человеком посередине» подвержены все соединения. Обычно при этом запоминаются верительные грамоты хоста и при последующем соединении с тем же хостом сравниваются с предъявленными.
Тестирование
Как и в большинстве других случаев применения криптографии к защите сети, довольно трудно доказать корректность системы, тестируя ее как черный ящик. Гораздо проще обнаружить такого рода проблемы в ходе анализа кода.
Примеры из реальной жизни
Атаки с «человеком посередине» хорошо известны. Мы неоднократно сталкивались с этой проблемой в «реальных» системах, когда за основу бралось какое–то решение, описанное в литературе, а затем над ним пытались надстроить криптосистему. Отметим еще, что этому греху подвержены многие системы, построенные на базе SSL или TLS.
Существуют даже инструменты для эксплуатации общих проявлений этой уязвимости, в том числе для атаки с «человеком посередине» на протоколы SSL и SSH. Например, dsniff.
Помимо распространенных случаев неправильного применения SSL/TLS, есть примеры, когда протокол аутентифицированного обмена ключами (скажем, Kerberos) используется для аутентификации, но выработанный ключ не применяется в криптографических целях. В результате нет никакой криптографической связи между аутентификацией и последующими сообщениями (обычно последующие сообщения вообще не подвергаются никакой криптографической обработке).
В настоящее время в базе данных CVE есть 15 сообщений, включающих фразу «man–in–the–middle». Но наш опыт показывает, что эта проблема куда более распространена, чем кажется на основе этой цифры.
Атака с «человеком посередине» на Novell Netware
Это пример неправильной сборки протокола из составных частей. В феврале 2001 года компания BindView обнаружила возможность атаки с «человеком посередине» против операционной системы Novell Netware, в которой использовался некорректный протокол обмена ключами и аутентификации. Этот «самописный» протокол был основан на схеме обмена ключами на базе алгоритма RSA, а не Диф–фи–Хеллмана. Авторы попытались выполнить аутентификацию по парольному протоколу, но не сумели надлежащим образом аутентифицировать сами сообщения, необходимые для обмена ключами. Протокол проверки пароля шифровался с помощью RSA–ключей, но пароль не использовался для проверки того, что ключи действительно принадлежат участникам. Противник мог подделать сервер, и тогда клиент передал бы противнику валидатор пароля, зашифрованный своим открытым ключом. После этого противник мог предъявить этот валидатор серверу, и это сработало бы, следовательно, противник мог выступить в роли «человека посередине».