it-swarm-ru.tech

Как лучше всего избегать xss-атак на сайте PHP?

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

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

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

<script

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

65
Rik Heywood

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

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

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

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

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

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

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

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

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

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

18
Jilles

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

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

12
Christian Studer

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

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

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

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

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

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

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

10
Matt Farina

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

.

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

7
Mason

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

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

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

4
Kornel

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

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

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

4
user319490

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

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

2
Niyaz

Лично я бы отключил 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 от пользователя (включая вас!).

2
Dave

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

2
barce

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

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

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

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

2
Alexey Feldgendler

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

2
Konrad Rudolph

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

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

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

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

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

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

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

1
Abeon

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

1
Night Owl

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

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

1
basszero

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

0
Darren22

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

0
dbr