Каковы лучшие практики для предотвращения атак xss на сайте PHP

Я настроил PHP так, что магические кавычки включены, а глобальные регистры отключены.

Я делаю все возможное, чтобы всегда вызывать htmlentities() для всего, что я выводил, полученного из пользовательского ввода.

Я также иногда ищу свою базу данных для общих вещей, используемых в xss, таких как...

<script

Что еще я должен делать и как я могу убедиться, что то, что я пытаюсь сделать, всегда сделано.

20 ответов

Решение

Экранирование ввода - не лучшее, что вы можете сделать для успешной профилактики XSS. Также выход должен быть экранирован. Если вы используете шаблонизатор Smarty, вы можете использовать |escape:'htmlall' модификатор для преобразования всех чувствительных символов в объекты HTML (я использую собственный |e модификатор, который является псевдонимом вышеупомянутого).

Мой подход к безопасности ввода / вывода:

  • хранить пользовательский ввод, не измененный (без экранирования HTML на входе, только экранирование с использованием DB с помощью подготовленных операторов PDO)
  • экранирование на выходе, в зависимости от того, какой формат вывода вы используете (например, HTML и JSON нужны разные правила экранирования)

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

Другими словами, вы можете избежать только в самый последний момент, когда данные "покидают" ваше приложение:

  • Элемент списка
  • Запись в XML-файл, экранирование для XML
  • Запись в БД, escape (для этой конкретной СУБД)
  • Написать письмо, бежать по электронной почте
  • так далее

Чтобы пойти коротко:

  1. Вы не знаете, куда идут ваши данные
  2. Данные могут на самом деле оказаться в более чем одном месте, требуя другого механизма выхода, НО НЕ ОБА
  3. Данные, сбежавшие по неверной цели, на самом деле не хороши. (Например, получите электронное письмо с темой "Перейти к бару Томми".)

Esp # 3 произойдет, если вы экранируете данные на входном слое (или вам нужно снова удалить их и т. Д.).

PS: я буду второй совет, чтобы не использовать magic_quotes, это чистое зло!

Есть много способов сделать XSS (см. http://ha.ckers.org/xss.html), и это очень трудно поймать.

Я лично делегирую это используемой в настоящее время среде (например, Code Igniter). Хотя он и не идеален, он может поймать больше, чем мои ручные процедуры.

Это большой вопрос.

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

Когда вы идете представить свой фильтр данных, что не должно быть там. Например, если нет причины присутствия JavaScript, найдите его и удалите. Самый простой способ сделать это - использовать функцию strip_tags и отображать только HTML-теги, которые вы разрешаете.

Затем возьмите то, что у вас есть, и передайте его htmlentities или htmlspecialchars, чтобы изменить то, что там, на символы ascii. Делайте это на основе контекста и того, что вы хотите получить.

Я бы также предложил отключить магические кавычки. Он был удален из PHP 6 и считается плохой практикой его использования. Подробности на http://us3.php.net/magic_quotes

Для получения более подробной информации проверьте http://ha.ckers.org/xss.html

Это не полный ответ, но, надеюсь, достаточно, чтобы помочь вам начать.

rikh Writes:

Я делаю все возможное, чтобы всегда вызывать htmlentities() для всего, что я выводил, полученного из пользовательского ввода.

See Joel's essay on Making Code Look Wrong for help with this

Библиотека шаблонов. Или, по крайней мере, именно так должны поступать библиотеки шаблонов. Для предотвращения XSS все выходные данные должны быть закодированы. Это не задача основной логики приложения / управления, она должна обрабатываться исключительно методами вывода.

Если вы разбросали htmlentities() по всему коду, общий дизайн будет неправильным. И, как вы предлагаете, вы можете пропустить одно или два места. Вот почему единственное решение - строгое кодирование html -> когда выходные переменные записываются в поток html/xml.

К сожалению, большинство библиотек шаблонов php только добавляют свой собственный синтаксис шаблонов, но не заботятся о кодировке вывода, или локализации, или проверке html, или чем-то важном. Может быть, кто-то еще знает правильную библиотеку шаблонов для php?

Я полагаюсь на PHPTAL для этого.

В отличие от Smarty и простого PHP, он по умолчанию экранирует все выходные данные. Это большой выигрыш для безопасности, потому что ваш сайт не станет уязвимым, если вы забудете htmlspecialchars() или же |escape где-то.

XSS - это специфическая для HTML атака, поэтому вывод HTML- подходящее место для ее предотвращения. Вы не должны пытаться предварительно фильтровать данные в базе данных, потому что вам может потребоваться вывести данные на другой носитель, который не принимает HTML, но имеет свои собственные риски.

Я считаю, что использование этой функции помогает исключить множество возможных xss-атак: http://www.codebelay.com/killxss.phps

Экранирования всего пользовательского ввода достаточно для большинства сайтов. Также убедитесь, что идентификаторы сеанса не попадают в URL, чтобы их нельзя было украсть из Referer ссылка на другой сайт. Кроме того, если вы разрешаете пользователям отправлять ссылки, убедитесь, что нет javascript: разрешены ссылки на протоколы; они выполнят скрипт, как только пользователь нажмет на ссылку.

"Магические кавычки" - это паллиативное средство от некоторых наихудших недостатков XSS, которое работает, избегая всего на входе, что-то не так по замыслу. Единственный случай, когда вы захотите использовать его, это когда вам абсолютно необходимо использовать существующее PHP-приложение, о котором известно, что оно написано небрежно в отношении XSS. (В этом случае у вас серьезные проблемы даже с "магическими кавычками".) При разработке собственного приложения вы должны отключить "магические кавычки" и следовать правилам, безопасным для XSS.

XSS, уязвимость межсайтового скриптинга, возникает, когда приложение включает строки из внешних источников (пользовательский ввод, извлеченные из других веб-сайтов и т. Д.) В свои [X]HTML, CSS, ECMAscript или другие выходные данные, анализируемые браузером, без надлежащего экранирования, надеясь что специальные символы, такие как меньше чем (в [X]HTML), одинарные или двойные кавычки (ECMAscript), никогда не появятся. Правильное решение - всегда экранировать строки в соответствии с правилами языка вывода: используя сущности в [X] HTML, обратную косую черту в ECMAscript и т. Д.

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

"Зарегистрировать глобальные переменные", хотя их отключение - определенно хорошая идея, решает проблему, совершенно отличную от XSS.

Если вы беспокоитесь о XSS-атаках, решение проблемы заключается в кодировании выходных строк в HTML. Если вы не забываете кодировать каждый выходной символ в HTML-формате, не существует способа выполнить успешную XSS-атаку.

Подробнее: Очистка пользовательских данных: как и где это сделать

Все эти ответы великолепны, но, по сути, решением XSS будет прекращение генерации HTML-документов путем манипулирования строками.

Фильтрация входных данных всегда хорошая идея для любого приложения.

Экранирование вывода с помощью htmlentities() и друзей должно работать до тех пор, пока он используется правильно, но это HTML-эквивалент создания SQL-запроса путем объединения строк с mysql_real_escape_string($var) - это должно работать, но меньше вещей может проверить вашу работу так сказать, по сравнению с подходом, подобным использованию параметризованных запросов.

Долгосрочное решение должно состоять в том, чтобы приложения создавали внутреннюю страницу, возможно, используя стандартный интерфейс, такой как DOM, а затем использовали библиотеку (например, libxml) для обработки сериализации в XHTML/HTML/ и т.д. Конечно, мы далеки от того, чтобы быть популярными и достаточно быстрыми, но в то же время мы должны создавать наши HTML-документы с помощью строковых операций, и это по своей природе более рискованно.

Лично я бы отключил magic_quotes. В PHP5+ это отключено по умолчанию, и лучше кодировать так, как будто его вообще нет, так как оно не скрывает все и будет удалено из PHP6.

Далее, в зависимости от того, какой тип пользовательских данных, которые вы фильтруете, будет диктовать, что делать дальше, например, если это просто текст, например имя, то strip_tags(trim(stripslashes())); это или для проверки диапазонов используйте регулярные выражения.

Если вы ожидаете определенный диапазон значений, создайте массив допустимых значений и пропустите эти значения только через (in_array($userData, array(...))).

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

Если у вас PHP5.2+, подумайте над использованием filter() и используйте это расширение, которое может фильтровать различные типы данных, включая адреса электронной почты. Документация не особенно хороша, но улучшается.

Если вам нужно обрабатывать HTML, вы должны рассмотреть что-то вроде PHP Input Filter или HTML Purifier. HTML Purifier также проверит HTML на соответствие. Я не уверен, что входной фильтр все еще разрабатывается. Оба позволят вам определить набор тегов, которые можно использовать, и какие атрибуты разрешены.

Что бы вы ни выбрали, всегда помните, никогда не доверяйте ничему, что входит в ваш PHP-скрипт от пользователя (включая вас!).

На сегодняшний день лучшим методом предотвращения XSS в приложении PHP является HTML Purifier (http://htmlpurifier.org/). Один незначительный недостаток заключается в том, что это довольно большая библиотека, и ее лучше всего использовать с кэшем кода операции, таким как APC. Вы можете использовать это в любом месте, где ненадежный контент выводится на экран. Гораздо тщательнее htmlentities, htmlspecialchars, filter_input, filter_var, strip_tags и т. Д.

  • Не доверяйте вводу пользователя
  • Сбросить все выходные тексты
  • Не используйте magic_quotes; посмотрите, есть ли вариант, специфичный для СУБД, или используйте PDO
  • Рассмотрите возможность использования файлов cookie только для HTTP, чтобы избежать любого вредоносного сценария, способного перехватить сеанс

Вы должны по крайней мере проверить все данные, поступающие в базу данных. И попробуйте проверить все данные, покидающие базу данных тоже.

mysql_real_escape_string хорош для предотвращения внедрения SQL, но XSS сложнее. Вы должны использовать preg_match, assign_tags или htmlentities, где это возможно!

Сделайте вам любые сеансовые куки (или все куки), которые вы используете HttpOnly. В этом случае большинство браузеров скрывают значение cookie от JavaScript. Пользователь по-прежнему может копировать файлы cookie вручную, но это помогает предотвратить прямой доступ к сценарию. У Stackru была эта проблема во время бета-тестирования.

Это не решение, просто еще один кирпич в стене

Используйте существующую пользовательскую библиотеку очистки для очистки всего пользовательского ввода. Если вы не приложите много усилий, реализация этого самостоятельно никогда не сработает.

Я считаю, что лучший способ - использовать класс, который позволяет вам связывать ваш код, чтобы вам никогда не приходилось беспокоиться о ручном экранировании ваших данных.

Трудно внедрить тщательное предотвращение инъекций sql /xss на сайт, который не вызывает ложных срабатываний. В CMS конечный пользователь может захотеть использовать <script> или же <object> что ссылки на элементы с другого сайта.

Я рекомендую всем пользователям установить FireFox с NoScript;-)

Другие вопросы по тегам