Укрощение @Интернет@

       

Уязвимость самостоятельных модулей


Редкое приложение состоит всего лишь из одного скрипта. Программная оснастка даже скромного сайта представляет собой десятки модулей, связанных друг с другом сложной иерархической зависимостью. Это порождает, по крайней мере, две проблемы: отсутствие контроля входных данных в служебных скриптах и возможность обхода системы авторизации.

Например, посетитель вводит в форму "Search" свой запрос, браузер извлекает его и передает поисковому скрипту, который отыскав файл документа с таким содержанием, передает его имя другому скрипту, предназначенному для его отображения.

Разработчик, предполагая, что второй скрипт всегда будет вызываться только первым, может и не предпринять никаких усилий по фильтрации ввода второго скрипта. Но ведь ничто не мешает злоумышленнику непосредственно вызывать этот скрипт самому, передав ему имя любого файла, который он хочет посмотреть (например, "/etc/passwd"), а не только *.html!

Любые данные, принимаемые любой программой извне, должны быть проверены! Необходимо убедиться в том, что запрошенный файл пользователю действительно можно смотреть. Этого не так-то просто добиться, как может показаться на первый взгляд – проверка запроса на соответствие именам запрещенных файлов ничего не решает – злоумышленник может запросить и базу данных клиентов сервера, и содержимое интересующего его скрипта, и т.д., – всего не перечислишь! Ограничение области видимости текущей директорией – так же не приводит к желаемому результату, во всяком случае, без фильтрации символов обращения к вышележащим каталогам.

Надежнее всего передавать не имя отображаемого файла, а его  номер в списке доступных для просмотра файлов. Существенные недостатки такого решения – сложность скрипта и необходимость постоянной коррекции списка доступных файлов при всяком добавлении или удалении новых документов на сервере.

Некоторые приемы позволяют избежать этих утомительных проверок. Например, пусть служебный скрипт принимает в качестве дополнительного параметра пароль, известный только вызываемому коду (и, разумеется, самому владельцу сайта). Тогда фильтрацию ввода необходимо осуществлять только в модулях, непосредственно взаимодействующих с пользователем, а во всех остальных можно опустить. При отсутствии ошибок реализации, связанных с обработкой и хранением пароля, злоумышленник не сможет непосредственно исполнить ни один служебный скрипт, если конечно, не сумеет подобрать пароль, чему легко противостоять (перебор даже пятисимвольного пароля по протоколу HTTP займет очень-очень много времени).


Такой подход снимает и другую проблему, – возможность обхода подсистемы авторизации "ручным" вызовом нужного скрипта. В сети нередко встречаются почтовые системы, работающие по следующему алгоритму: "входной" скрипт проверяет имя и пароль пользователя и, если они верны, передает одно лишь имя пользователя (без пароля!) другому скрипту, непосредственно работающему с почтовым ящиком. Злоумышленник, вызвав последний скрипт напрямую, получит доступ к корреспонденции любого пользователя! Удивительно, но подобная ошибка встречается и в некоторых Интернет-магазинах: скрипту, осуществляющему покупку, передают не полную информацию о пользователе (номер кредитной карты, адрес и т.д.), а идентификатор, по которому этот скрипт и получает все эти сведения из базы данных, хранящейся на сервере. Если идентификатор представляет небольшое предсказуемое число (как часто и бывает), злоумышленник сможет заказать товар от имени любого из постоянных покупателей магазина.

Сюда же относятся и ошибки обработки динамически генерируемых форм. Чтобы скрипт мог отличить одного посетителя странички от другого, он добавляет в форму особое скрытое поле, содержащее имя пользователя, введенное им при регистрации (так, например, функционирует большинство чатов). Злоумышленник может сохранить переданную ему страницу на диск, модифицировать по своему усмотрению скрытое поле, выдавая тем самым себя за другое лицо.

Не стоит надеяться на проверку переменной HTTP_REFERER – она заполняется самим HTTP-клиентом и может содержать все, что угодно! Грамотно спроектированный скрипт должен помещать в скрытое поле не только имя пользователя, но и его пароль. Для чатов такая защита вполне подойдет, но в более ответственных случаях пароль следует шифровать по алгоритму с несимметричными ключами или хешировать по схеме "запрос-отклик". Иначе злоумышленнику, перехватившему трафик, не составит большого труда его узнать. Техника шифрования – тема отдельного большого разговора, в контексте же настоящей книги вполне достаточно указать на необходимость шифрования, устойчивую к перехвату, а как ее реализовать – это уже другой вопрос.

Важное замечание: никогда не следует передать секретные данные методом GET, поскольку, он помещает их в тело URL, а браузеры в специальной переменной хранят URL предыдущего посещенного сайта и передают эту переменную при переходе c одного сервера к другому. Конечно, вероятность того, что им окажется сервер злоумышленника, очень невелика, но все-таки этой угрозой не стоит пренебрегать.

Кроме того, браузеры Internet Explorer и Netscape Navigator заносят в общедоступный журнал URL все посещенные за такой-то период сайты, – на компьютерах коллективного использования это приводит к возможности перехвата секретной информации, переданной на сервер методом GET. В отличие от него, метод POST помещает содержимое запроса в HTTP-заголовок, что намного безопаснее.


Содержание раздела