Читаем Защита веб-приложений на Perl онлайн бесплатно
Защита веб-приложений на Perl
Сборник практических правил и советов с примерами и разъяснениями. Главным образом речь идет о языке Perl и сервере Apache, но многое из сказанного справедливо для других подобных средств разработки. Приведённые примеры кода не претендуют на универсальность и законченность, однако, они все проверены и работают.
Компьютеры и Интернет / ОС и Сети, интернетВторая версия статьи (включает 18 пунктов из первой версии), обновлена: 5 июня 2012.
Оригинал статьи: http://dj-andrey.ru/articles/perl-web-application-security
Сборник практических правил и советов с примерами и разъяснениями. Главным образом речь идет о языке Perl и сервере Apache, но многое из сказанного справедливо для других подобных средств разработки.
Приведённые примеры кода не претендуют на универсальность и законченность, однако, они все проверены и работают на свежих версиях Perl. Почти все пункты уже применялись в реальных скриптах, и я чуть ли не каждую неделю с удовольствием читаю отчеты об успешно отраженных нападениях на сервера.
Не стройте свою защиту только лишь на средствах HTML. Таких как input типа hidden, задание параметров вроде readonly, disabled, maxlength и т.д. Всё это легко обходится построением запроса самостоятельно.
Есть несколько инструментов для Firefox. Например, Firebug
В Firebug, например, скрытые элементы редактируются на ура. Аттрибуты maxlength, disabled, readonly снимаются очень просто. HTML-код, сгенерированный на JavaScript просматривается полноценно, а изменения отражаются немедленно.
Кстати, Firebug в первую очередь – прекрасное средство для отладки.
Все верно выставленные параметры и JavaScript-обработчики (не в качестве защиты) нужны для нормального пользователя, чтобы он понял, сколько он может вводить, где нельзя нажать и т.п. А ненормальный пользователь всё равно построит запрос руками. Собственно, остальная часть статьи во многих местах рассказывает вам, как защититься от построенного самостоятельно поддельного запроса.
Не доверяйте тому, что пришло от пользователя в Cookies. Только ленивый взломщик не станет пробовать их поменять (например, в Opera
В первую очередь надо написать проверку на стороне сервера, а уже только потом на клиенте. В случае нехватки времени, клиентскую проверку можно отложить до следующей версии, но вас уже не сломают. Не надейтесь на OnSubmit, OnKeyPress и прочий JavaScript. Он отключается. Отладка не просто доступна, она кое-где даже удобна. JavaScript – только как средство защиты от ошибок нормальных пользователей и чтобы не мучить сервер обработкой заведомо неверно заполненных форм.
Не важно, насколько крут ваш любимый обфускатор
Если форма отправляется, к примеру, методом POST, сервер должен отказаться принимать любой другой метод. Исключением из правил может стать лишь скачивание файла: там нужен как GET, так и HEAD.
Как вам перспектива массовой накрутки счетчика злоумышленником, либо добавление записей флудером при помощи метода HEAD? Копеечный трафик, а какой эффект!
Любой param или cookie (в терминах модуля CGI.pm) НУЖНО проверить или отфильтровать. Исключение – это данные, которые не будут фрагментом SQL-запроса, регулярного выражения, вываливаться в HTML, выполняться на сервере или сохраняться для последующей передачи клиенту.
Данные от пользователя без фильтрации нельзя использовать в регулярных выражениях.
Пример неправильного кода:
Чтобы избежать обработки ”регулярных“ метасимволов, нужно писать переменные между \Q и \E:
Есть функция под названием quotemeta. Она подготавливает строку символов к безопасному помещению в регулярное выражение. Все не алфавитно-цифровые символы будут проэкранированы обратным слэшэм.
Не позволяйте действиям, создающим уникальные по определению данные, выполняться более одного раза. Это собьет с толку нормального пользователя и позволит злоумышленнику намусорить в базе. Всегда останавливайте обработку и сообщайте пользователю, почему система отказала в выполнении действия. Вот несколько примеров:
• Не может быть двух пользователей с совпадающими логинами, email или одинаковыми паспортными данными.
• Не должно появиться двух пунктов меню или в списке на одном уровне с полностью совпадающим названием.
• Не может существовать двух предметов под названием «Физическая география» с разными id.
И так далее. Можно привести массу примеров, главное – вспоминать об этом принципе при проектировании всего нового. В борьбе с неуникальностью помогут уникальное индексирование или ручная проверка select-ом перед вставкой.
Последнее время стало модно проверять данные с помощью Ajax прямо во время заполнения форм.
Делая так, вы не только заблаговременно предупредите пользователя об ошибке, но и избавите его от лишних действий – ему не придётся возвращаться на предыдущую страницу кнопкой Back, Backspace или JavaScript-ссылкой, рискуя потерять введённые данные, потому как не все браузеры одинаково бережно относятся к данным форм на предыдущих страницах, либо сами избавляетесь от лишней работы по генерации в ответ на POST этой же формы, но с помеченными ошибками.
Создайте альтернативные функции считывания данных cookie или param. Пользуйтесь только ими там, где наличие параметра обязательно и тип данных не меняется. Они должны работать как обычные, но если только формат данных не соответствуют ожидаемому, программа прекратит выполнение обработки запроса. Для начала любому серьёзному проекту точно понадобятся функции валидации дат, чисел, диапазонов чисел и нахождения переданной строки в заданном списке строк или поле таблицы базы данных.
Примеры таких функций:
И тому подобные.
Примеры использования:
Но этого недостаточно. Всегда дотошно представляйте себе ситуацию, обдумайте типичные ошибки и опечатки. В сообщении об ошибке покажите пример правильно заполненного поля. Наконец, включите логику.
Вот пара простых примеров:
• Если вы спрашиваете у пользователя, когда он создал свой сайт, не позволяйте ему указать 1634 год (тогда интернета вроде не было) или дату в будущем.
• Или вы спрашиваете возраст пользователя. Не нужно позволять ему указывать 300 лет. К сожалению, столько не живут. Правда в этом конкретном случае лучше быть оптимистом, да и деваться некуда – нужно ставить с запасом. Зато представьте себе, какая радость, когда какой-то пользователь пожалуется на ограничение в 150 лет :)
В формах ввода данных в базу проставляйте параметр maxlength для текстовых полей, равный размеру поля в базе. Не ограничивайтесь этим, всегда обрезайте текст и на сервере.
HTML:
Perl:
Можно сделать обёртку:
Используйте метод quote интерфейса DBI, если текст, введенный пользователем, нужно использовать в SQL-запросах. Либо биндинг параметров, что обязательно для BLOB-полей и полезно для простого текста. Этим вы будете защищены от SQL-Injection атак.
Примеры с биндингом:
Пример с quote:
Смешивать quote и биндинг нельзя!
XSS может быть не менее опасен, чем дыра другого класса. Только представьте себе, что вы залогинились и просматриваете HTML, в который злоумышленник встроил зловредный JavaScript, переправляющий вас на URL, который для вашей системы, к примеру, является командой грохнуть информацию или отправить ее на сторону.
Пример. Представьте себе, что вашу форму заполнили вот так:
А если там будет что-то вроде этого. Как вам?
Защищайтесь даже от не вполне очевидных опасностей, скажем, от поля User-Agent запроса (который часто светится в логах или статистике, что, как правило, дело админское, а там XSS еще более опасен).
Позволяйте вставлять HTML только там, где это действительно необходимо. Лучше дайте пользователю редактор вроде FCKeditor
Обратите внимание на готовые модули для чистки HTML:
HTTML::Scrubber
HTML::Detoxifier
HTML::TagFilter
Не провоцируйте взломщика к дальнейшим действиям – не говорите, в какой строке и в каком файле произошла ошибка. Не цитируйте сообщений интерпретатора, не показывайте SQL-запросы. Используйте mod_rewrite
Не доверяйте никому: неавторизованному проходящему мимо серферу, пользователю и даже администратору. Почему? Любая функция, даже редко используемая или которая только для администратора должна быть крепко защищена не хуже других. Представьте, админ тоже человек, он может забыть разлогиниться, или он может просто оказаться недобросовестным и сам попытаться искать какой-нибудь SQL-Injection в админке, рассчитывая на то, что, ну, уж админу-то вроде доверять должны…
В ряде случаев вам не удастся полноценно восстановить картину действий пользователей по логам Apache. Ведите собственный журнал безопасности. Разумеется, для экономии хранить в нём следует лишь критические действия пользователей, такие как регистрация, вход/выход, смена пароля, неудачные попытки входа, поведение, похожее на перебор паролей или поиск уязвимостей, IP-адреса (и Proxy, если есть), User-Agent'ы, дату/время и тому подобное. Это позволит намного удобнее анализировать действия и реагировать на инциденты эффективнее.
Дырка снаружи на порядок хуже, чем та, которой может воспользоваться только авторизованный пользователь. Авторизованных всегда меньше, и они просто по определению должны в подавляющем большинстве быть заинтересованы в том, чтобы не навредить. А вот несвязанных с системой злонамеренных людей может быть больше. Им наплевать, что своими действиями они могут уронить сервер, уничтожить чужой труд. Обращайте повышенное внимание к тому, что можно сделать без авторизации.
Если вы считаете, что ЭТОГО никто никогда не сделает или не додумается, и не станете полноценно от ЭТОГО защищаться, знайте: рано или поздно найдется такой маньяк, который обязательно сделает именно ЭТО. Либо сложатся обстоятельства, которые вы не обрабатываете, так как считаете маловероятными.
Загрузка файлов на сервер.
Лучше задать список разрешенных расширений файлов, чем задавать список запрещенных. Если какое-либо расширение будет забыто, пользователи пожалуются, что не смогли загрузить файл с таким расширением. Это гораздо лучше, чем некто сумеет загрузить нечто нехорошее (что-то, что вы забыли запретить).
Для архивов, скриптов, исполняемых, документов и других подобных файлов обязательна антивирусная проверка. Многие любят перекладывать это на плечи пользователя, скачивающего файлы. Почему бы не уменьшить проблему прямо при загрузке? Понимаю, что это не решает всех проблем, ведь можно написать новый вирус и положить его исключительно на атакуемый сервер (чтобы в антивирусные базы не сразу попал), но это не означает, что можно пренебрегать возможностью организовать автоматическое отсеивание известных вирусов.
Не плохо бы заодно проверять сигнатуры файлов. Если прислали с расширением jpg, то и по сигнатуре это должен быть строго JPEG, если zip – то ZIP и ничто иное, иначе отказывать. Разумеется, это касается лишь тех форматов, у которых есть стандартная обязательная сигнатура. Вспомните, вам наверное хотя бы раз на форумах попадался какой-нибудь URL с комментарием вроде «скачайте и смените расширение на rar» – скорее всего это обманутый сервер, сохранивший файл, не проверив сигнатуру. На UNIX-подобных системах для автоматической проверки есть утилита file, по нему есть manual. Если формат редкий, его придется проверить вручную. Описания форматов ищите на сайтах вроде Wotsit.org
Ко временной папке, куда будут загружаться файлы перед обработкой или проверкой не должно быть доступа. Когда загрузка завершена, сделайте (если требуется) необходимые действия, преобразования и тому подобное, и только затем перемещайте в доступное извне место.
В папке, куда попадают загруженные файлы не должны быть включены SSI, PHP, Options ExecCGI, и прочее. Как вариант: отдавайте файлы не вживую, а через скрипт, это позволит вам собрать больше информации и создаст лучшие условия для принятия решений на лету.





