Я хочу предотвратить атаки XSS в своем веб-приложении. Я обнаружил, что HTML-кодирование вывода действительно может предотвратить атаки XSS. Теперь проблема в том, как мне HTML-кодировать каждый вывод в моем приложении? Есть ли способ автоматизировать это?
Я ценю ответы на JSP, ASP.net и PHP.






Если вы действительно кодируете HTML каждый вывод, пользователь увидит простой текст & lt; html & gt; вместо работающего веб-приложения.
Обновлено: если вы кодируете HTML каждый ввод, у вас возникнут проблемы с принятием внешнего пароля, содержащего <и т. д.
Вы не кодируете ввод перед его обработкой. Вы кодируете ввод, когда выводите его пользователю ... так работают XSS-атаки.
Вы не хотите кодировать весь HTML, вам нужно только HTML-кодирование любого пользовательского ввода, который вы выводите.
Для PHP: htmlentities и htmlspecialchars
Фактически, вы должны кодировать весь текст внутри тега или атрибута HTML - независимо от того, исходил ли он от пользователя. Например: <a title = "Barnes & Noble's Books">Barnes & Noble's Books</a>
Хороший способ, которым я избегал всех вводимых пользователем данных, - это написать модификатор для smarty, который экранирует все переменные, передаваемые в шаблон; кроме тех, к которым прикреплено | unescape. Таким образом, вы предоставляете HTML-доступ только тем элементам, к которым вы явно предоставляете доступ.
У меня больше нет этого модификатора; но примерно такую же версию можно найти здесь:
http://www.madcat.nl/martijn/archives/16-Using-smarty-to-prevent-HTML-injection..html
В новом выпуске Django 1.0 это работает точно так же, Джей :)
Вы можете обернуть эхо / печать и т. д. В свои собственные методы, которые затем можно использовать для выхода из вывода. т.е. вместо
echo "blah";
использовать
myecho('blah');
у вас даже может быть второй параметр, который отключает экранирование, если вам это нужно.
В одном проекте у нас был режим отладки в наших функциях вывода, в котором весь выводимый текст, проходящий через наш метод, был невидимым. Тогда мы знали, что ничего, что осталось на экране, НЕ БЕЗОПАСНО! Было очень полезно выслеживать эти непослушные неэкранированные биты :)
Лично я предпочитаю старательно кодировать что-либо, поступающий из базы данных, бизнес-уровня или от пользователя.
В ASP.Net это делается с помощью Server.HtmlEncode(string).
Причина такого кодирования чего-либо заключается в том, что даже свойства, которые вы можете считать логическими или числовыми, могут содержать вредоносный код (например, значения флажков, если они выполнены неправильно, могут возвращаться в виде строк. Если вы не кодировали их раньше отправка вывода пользователю, значит, у вас есть уязвимость).
Единственный способ по-настоящему защитить себя от такого рода атак - это строго фильтровать все входные данные, которые вы принимаете, в частности (хотя и не исключительно) из общедоступных областей вашего приложения. Я бы порекомендовал вам взглянуть на Класс фильтрации PHP Дэниела Морриса (полное решение), а также на пакет Zend_Filter (набор классов, которые вы можете использовать для создания собственного фильтра).
Когда дело доходит до веб-разработки, я предпочитаю PHP, поэтому приношу свои извинения за предвзятость в моем ответе.
Киран.
Одна вещь, которую вы делаете не должен, - это фильтруете входные данные по мере их поступления. Люди часто предлагают это, поскольку это самое простое решение, но оно приводит к проблемам.
Входные данные могут быть отправлены в несколько мест, помимо вывода в формате HTML. Например, он может храниться в базе данных. Правила фильтрации данных, отправляемых в базу данных, сильно отличаются от правил фильтрации вывода HTML. Если вы закодируете все в HTML при вводе, вы получите HTML в своей базе данных. (Вот почему функция PHP "волшебных кавычек" - плохая идея.)
Вы не можете предвидеть все места, куда будут перемещаться ваши входные данные. Безопасный подход - подготовить данные прямо перед, которые он куда-то отправил. Если вы отправляете его в базу данных, избегайте одинарных кавычек. Если вы выводите HTML, избегайте сущностей HTML. И после того, как он куда-то отправлен, если вам все еще нужно работать с данными, используйте исходную версию без экранирования.
Это больше работы, но вы можете сократить ее, используя механизмы шаблонов или библиотеки.
Только при санации html-тегов вы не учли SQL-инъекцию.
«Если вы отправляете его в базу данных, избегайте одинарных кавычек». Идея та же, что и с HTML; если строка будет включена в инструкцию SQL, вы должны правильно ее закодировать, чтобы она рассматривалась как строка. И самое время сделать это, когда вы создаете SQL, а не раньше.
было хорошее эссе от Джоэла о программном обеспечении (я думаю, что неправильный код выглядит неправильно, я разговариваю по телефону, иначе у меня был бы для вас URL), в котором рассказывалось о правильном использовании венгерской нотации. Краткая версия будет выглядеть примерно так:
Var dsFirstName, uhsFirstName : String;
Begin
uhsFirstName := request.queryfields.value['firstname'];
dsFirstName := dsHtmlToDB(uhsFirstName);
В основном префикс ваших переменных чем-то вроде "нас" для небезопасной строки, "ds" для безопасности базы данных, "чс" для безопасности HTML. Вы хотите кодировать и декодировать только там, где вам это действительно нужно, а не все. Но используя их префиксы, которые выводят полезный смысл, глядя на ваш код, вы очень быстро увидите, если что-то не так. И в любом случае вам понадобятся другие функции кодирования / декодирования.
По-настоящему короткая версия - никогда не использовать венгерскую нотацию, потому что, если вы не используете IDE, которая может сразу сказать вам, к какому типу принадлежит переменная, или предоставить прилично описательное имя переменной, вы делаете это неправильно.
Что касается JSP, вы можете съесть свой торт и съесть его с помощью тега c: out, который по умолчанию экранирует XML. Это означает, что вы можете привязать свои свойства как необработанные элементы:
<input name = "someName.someProperty" value = "<c:out value='${someName.someProperty}' />" />
При привязке к строке someName.someProperty будет содержать ввод XML, но при выводе на страницу он будет автоматически экранирован для предоставления сущностей XML. Это особенно полезно для ссылок для проверки страницы.
К сожалению, c:out недостаточно для атрибутов html :-(
@ PeterŠtibraný Не могли бы вы развить свою точку зрения? Было бы хорошо понять, почему c:out не рекомендуется для экранирования атрибутов HTML.
@Jimadine: в то время как c: out избегает одинарных и двойных кавычек, Internet Explorer также поддерживает обратные кавычки (`) в качестве разделителей атрибутов, и поэтому их также необходимо экранировать. Об этом есть забавная статья на wonko.com/post/html-escaping
@ PeterŠtibraný Интересно, я этого не знал. Спасибо за информацию.
Кодирование вывода - безусловно, лучшая защита. Проверка ввода хороша по многим причинам, но не на 100% защиту. Если база данных заражена XSS через атаку (например, ASPROX), ошибку или злонамеренность, проверка ввода ничего не дает. Кодировка вывода по-прежнему будет работать.
У OWASP есть хороший API для кодирования вывода HTML, чтобы использовать его как текст HTML (например, абзац или содержимое <textarea>) или как значение атрибута (например, для тегов <input> после отклонения формы):
encodeForHTML($input) // Encode data for use in HTML using HTML entity encoding
encodeForHTMLAttribute($input) // Encode data for use in HTML attributes.
Проект (версия PHP) размещен в http://code.google.com/p/owasp-esapi-php/, а также доступен для некоторых других языков, например .СЕТЬ.
Помните, что вы должны кодировать все (не только ввод пользователя) и как можно позже (не при сохранении в БД, а при выводе ответа HTTP).
Все с точки зрения ASP.NET или PHP - это просто строка в буфере ответа.