19 смертных грехов, угрожающих безопасности программ
Шрифт:
Несложное моделирование угрозы обнаруживает изъяны, свойственные описанному подходу. Первый состоит в том, что перечень проверяемых программ не аутентифицируется. Перехватив ответ или просто подставив фальшивый сервер, противник может сказать клиенту, что тот должен проверять. В частности, он может подавить проверку заведомо уязвимых программ или заменить безупречную программу уязвимой.
CVE–1999–0024
Цитата из бюллетеня CVE: «Отравление кэша DNS через систему BIND в результате предсказания идентификатора запроса».
Более подробно об этой проблеме можно прочитать на странице www.securityfocus.com/bid/678/discussion. Суть дела в том, что предсказание порядкового номера DNS–запроса позволяет противникуИскупление греха
Как и во многих других случаях, первым шагом к искуплению греха должно стать уяснение сути проблемы. Затем посмотрите, актуальна ли эта проблема для вашего приложения. Если вы дочитали до этого места, то, по крайней мере, понимаете, насколько ненадежной может быть информация, возвращаемая DNS–cep–вером.
В отличие от многих других грехов, мы не можем привести конкретные детали, однако упомянем ряд полезных инструментов. Один из самых простых подходов заключается в том, чтобы защищать все соединения по протоколу SSL. Если речь идет о программах, работающих в пределах компании, то имеет смысл установить корпоративный сервер сертификатов и выпустить сертификаты для всех клиентских систем.
Другой вариант – воспользоваться протоколом IPSec. Если IPSec работает поверх Kerberos, то часть работы по аутентификации клиентов и серверов за вас уже проделана; есть уверенность, что любая система, соединившаяся с вашей, как минимум, находится в той же области Kerberos (в терминологии Windows, домене или лесу). IPSec на основе сертификатов тоже работает неплохо, хотя для корректного конфигурирования и эксплуатации инфраструктуры открытых ключей (PKI) потребуется приложить некоторые усилия. Недостатком всех решений на базе IPSec является то, что информация о структуре сети недоступна прикладному уровню, стало быть, ваше приложение отдано на милость сетевому администратору. Есть еще один способ: потребовать наличия IPSec–защищенного участка сети между вашей системой и DNS–сервером. Тогда, по крайней мере, есть гарантия, что вы общаетесь именно с вашим DNS–сервером, поэтому степень доверия к разрешению внутренних имен повышается. Обратите внимание: мы НЕ сказали, что проблема решена, она лишь несколько утратила остроту.
Если аутентификация производится через Kerberos или с помощью внутреннего механизма Windows, причем установлены последние версии клиентов и серверов, то протокол препятствует атакам с «человеком посередине». Впрочем, взлом паролей по–прежнему возможен.
Если приложение особо важно, то самый безопасный способ решить проблему – это воспользоваться криптографией с открытым ключом и подписывать данные, передаваемые в обоих направлениях. Если требуется еще и конфиденциальность, примените открытый ключ для шифрования одноразового симметричного сеансового ключа и доставьте его другой системе. После того как сеансовый ключ выбран, конфиденциальность данных можно считать обеспеченной, а подписанный дайджест сообщения доказывает, откуда оно поступило. Работы, конечно, много, и надо бы пригласить специалиста, который может оценить криптографический протокол, но такой подход наиболее надежен.
Дешевый и малопривлекательный способ решения проблемы состоит в том, чтобы
Другие ресурсы
□ Building Internet Firewalls, Second Edition by Elizabeth D. Zwicky, Simon Cooper and D. Brent Chapman (O\'Reilly, 2000)
□ OzEmail:dns_spoofing.pdf
Резюме
Рекомендуется
□ Применяйте криптографические методы для идентификации клиентов и серверов. Проще всего использовать для этой цели SSL.
Не рекомендуется
□ Не доверяйте информации, полученной от DNS–сервера, она ненадежна!
Стоит подумать
□ Об организации защиты по протоколу IPSec тех систем, на которых работает ваше приложение.
Грех 16. Гонки
В чем состоит грех
Гонка (race condition), по определению, может возникнуть, когда есть две программы, выполняемые в разных контекстах (процессах или потоках). Эти программы могут прерывать друг друга, и при этом каждая изменяет один и тот же ресурс. Если вы думаете, что некоторая короткая последовательность команд или системных вызовов обязательно выполняется атомарно и не может быть прервана другим потоком либо процессом, то совершаете типичную ошибку. Даже имея неопровержимые доказательства существования ошибки, многие программисты склонны ее недооценивать. Но ведь на практике многие системные вызовы выполняют тысячи (иногда миллионы) команд, поэтому сплошь и рядом не успевают завершиться в течение кванта времени, отведенного текущему процессу или потоку.
Мы не будем вдаваться в детали, но сообщим, что простая гонка в многопоточной «ping–звонилке» как–то вывела из строя сервис–провайдера Интернет почти на сутки. Неправильно реализованная блокировка ресурса привела к тому, что приложение посылало ping–запросы на один и тот же IP–адрес с очень высокой скоростью. Знать о существовании гонок важно потому, что чаще всего они проявляются на самых быстродействующих процессорах, прежде всего в системах с двумя процессорами. Это аргумент в пользу того, чтобы руководство обеспечило всех разработчиков быстрыми двухпроцессорными машинами!
Подверженные греху языки
Как и во многих других случаях, гонка может возникнуть в программе, написанной на любом языке. Языки высокого уровня, не поддерживающие потоков и разветвления процессов, не подвержены некоторым видам гонок, но сравнительно низкая производительность таких языков делает их уязвимыми для атак, основанных на разнице во времени между моментом проверки и моментом использования ресурса (time of check to time of use – TOCTOU).
Как происходит грехопадение
Основная ошибка, которая приводит к возникновению гонки, – это программирование с побочными эффектами, против чего предостерегают все учебники. Если функция не реентерабельна и два потока одновременно исполняют ее, то рано или поздно произойдет ошибка. Как вы теперь уже, наверное, понимаете, почти любая программная ошибка при некотором невезении и достаточных усилиях, приложенных противником, может быть превращена в эксплойт. Вот иллюстрация на С++: