19 смертных грехов, угрожающих безопасности программ
Шрифт:
String ^s = Path::GetTempFileName;
Дополнительные защитные меры
При работе с сервером Apache проверьте, чтобы в файле httpd.conf не было излишних директив FollowSymLink. Правда, когда эта директива удаляется, производительность слегка падает.
Другие ресурсы
□ «Secure programmer: Prevent race conditions» by David Wheeler: www–106. ibm.com/developerworks/linux/library/l–sprace.html?ca=dgr–lnxw07RACE
□ Building Secure Software by John Viega and Gary McGraw (Addison Wesley), Chapter 9,
□ Writing Secure Code, Second Edition by Michael Howard and David C. LeBlanc (Microsoft Press, 2002), Chapter 11 «Canonical Representation Issues»
□ Perl 5 Reference Guide в формате HTML от Рекса Суэйна: www.rexswain.com/ perl5.html#filetest
□ «Secure Programming for Linux and Unix HOWTO – Creating Secure Soft–ware» by David Wheeler: www.dwheeler.com/secure–programs/
Резюме
Рекомендуется
□ Тщательно проверяйте, что вы собираетесь принять в качестве имени файла.
Не рекомендуется
□ Не принимайте слепо имя файла, считая, что оно непременно соответствует хорошему файлу. Особенно это относится к серверам.
Стоит подумать
□ О хранении временных файлов в каталоге, принадлежащем конкретному пользователю, а не в общедоступном. Дополнительное преимущество такого решения – в том, что приложение может работать с минимальными привилегиями, поскольку всякий пользователь имеет полный доступ к собственному каталогу, тогда как для доступа к системным каталогам для временных файлов иногда необходимы привилегии администратора.
Грех 15. Излишнее доверие к системе разрешения сетевых имен
В чем состоит грех
Этот грех понятнее многих других – в большинстве реальных ситуаций у нас нет другого выхода, как доверять системе разрешения имен. В конце концов, не станете же вы запоминать, что– это IP–адрес одного из многих англоязычных серверов, доступных по имени www.google.com. И никому не хочется модифицировать файлы в своей системе, когда что–то меняется в адресации.
Проблема же в том, что многие разработчики не понимают, насколько уязвима система разрешения имен и как ее легко атаковать. Хотя для большинства приложений основной службой разрешения имен является DNS, но в больших сетях из Windows–машин применяется также служба WINS (Windows Internet Name Service). У разных служб есть некоторые специфические особенности, но все они страдают общим недостатком: им нельзя доверять полностью.
Подверженные греху языки
В отличие от многих других грехов степень доверия к службе разрешения имен совершенно не зависит от языка программирования. Проблема в изъянах самой инфраструктуры, которой мы пользуемся, и если вы не понимаете, в чем эта проблема состоит, то и ваша программа, вероятно, будет содержать ошибки.
Вместо того чтобы рассматривать ситуацию с точки зрения греховных языков программирования, мы поговорим о том, какие приложения уязвимы. Основной вопрос: должно ли приложение знать, какая машина соединилась с вашей или с какой системой соединились вы.
Если в приложении применяется какой–нибудь вид аутентификации, особенно ее слабые формы, или по сети передаются зашифрованные данные, то, наверное, нужен надежный способ идентифицировать сервера, а в некоторых случаях и клиента.
Если же приложение принимает только анонимные соединения и возвращает данные в открытом виде, то сведения об адресе клиента нужны разве что для протоколирования. Но даже
в этом случае принимать дополнительные меры для аутентификации клиента не всегда практично.Как происходит грехопадение
Мы рассмотрим принципы работы DNS, а затем попробуем смоделировать угрозу. Клиент хочет найти некий сервер, скажем, www.example.com. Он посылает запрос DNS–серверу с просьбой сообщить IP–адрес (или несколько адресов), соответствующий доменному имени www.example.com. Важно отметить, что служба DNS работает по протоколу UDP, так что вы лишены даже той эфемерной защиты, которую предоставляет протокол TCP. Получив запрос, DNS–сервер смотрит, есть ли у него готовый ответ. Ответ имеется двух случаях: если данный сервер является руководящим (authoritative) для домена example.com или сохранил в кэше ответ на вопрос о том же имени, поступивший от какого–то другого компьютера. Если ответа нет, сервер запросит у одного из корневых серверов, где найти руководящий сервер имен для домена example.com (это может повлечь за собой еще один запрос к серверу домена .com, если example.com отсутствует в кэше). Узнав адрес руководящего сервера, первоначальный сервер пошлет ему еще один запрос и на этот раз получит окончательный ответ. К счастью, в систему DNS встроена избыточность: на каждом уровне работает несколько серверов, что позволяет защититься от случайных сбоев, не связанных с атаками. Но, как мы видели, шагов много, так что злоумышленник может нанести удар в разные места.
Во–первых, откуда вы знаете, что ответил действительно ваш сервер имен? Вы послали запрос на некоторый IP–адрес с определенного порта в вашей системе. Вы знаете, какое имя указали в запросе. Если бы все было хорошо, то, получив в ответ на запрос об адресе сервера www.example.com адрес сервера evilattackers.org, ответ следовало бы отбросить. Да еще с запросом связан 16–разрядный идентификатор – но предназначен он вовсе не для защиты, а чтобы не путать запросы от нескольких приложений, работающих на одной и той же машине.
Теперь посмотрим, что может пойти не так. Прежде всего, адрес настоящего сервера имен. Противнику нетрудно узнать этот адрес, особенно если он находится в той же сети, что и вы; почти наверняка в этом случае вы используете один и тот же DNS–сервер. Другой способ заключается в том, чтобы заставить систему запрашивать IP–адрес у DNS–сервера, контролируемого противником. Возможно, вам кажется, что это условие трудновыполнимо, но, принимая во внимание историю некоторых реализаций DNS–серверов, приходится с сожалением признать, что перспектива напороться на контролируемый противником сервер имен реальна. Итак, предположим, что противнику известен IP–адрес вашего DNS–сервера. Думаете, клиент будет настаивать на том, чтобы ответ пришел именно с того IP–адреса, на который был послан запрос? Увы, иногда ответы поступают с другого адреса по естественным причинам, поэтому некоторые определители имен не требуют соблюдения этого условия.
Далее, ответ должен прийти на тот же порт, с которого был отправлен запрос. Теоретически существует 64К портов, но на практике их меньше. В большинстве операционных систем динамические порты выделяются из ограниченного диапазона, в случае Windows это номера от 1024 до 5000, так что область поиска ограничена 12 битами вместо 16. Хуже того, номера портов обычно начинаются с 1024 и возрастают на единицу. Поэтому можно считать, что противник без особого труда сможет угадать номер порта.
Есть еще идентификатор запроса, но во многих реализациях он тоже возрастает монотонно, так что и его угадать несложно. Если противник находится в той же подсети, что и клиент, то атака становится тривиальной. Даже при наличии в сети коммутатора противник может увидеть запрос и получить всю информацию, необходимую для изготовления подложного ответа.