Лучшие практики Java для предотвращения межсайтовых сценариев

Я просмотрел десятку основных уязвимостей OWASP и обнаружил, что межсайтовый скриптинг — это то, что нам нужно делать. Было несколько рекомендуемых решений. Один заявил, что не используйте проверку «черного списка» для обнаружения XSS на входе или для кодирования вывода. Поиск и замена всего нескольких символов (< и > и других подобных символов или фраз, таких как script) неэффективны и успешно атакованы. Даже непроверенный тег “<b>” в некоторых контекстах небезопасен. XSS имеет удивительное количество вариантов, позволяющих легко обойти проверку черного списка. В другом решении говорилось, что сильная кодировка вывода. Перед визуализацией убедитесь, что все предоставленные пользователем данные закодированы соответствующим образом (в HTML или XML в зависимости от механизма вывода). Итак, каков наилучший способ предотвратить межсайтовые сценарии для проверки и замены ввода или кодирования вывода?


person Community    schedule 21.07.2009    source источник
comment
Возможный дубликат: stackoverflow .com/questions/24723/   -  person aem    schedule 21.07.2009
comment
Дубликат: stackoverflow.com/ вопросы/2658922/   -  person BalusC    schedule 20.09.2020


Ответы (3)


Обычной практикой является HTML-экранирование любых управляемых пользователем данных во время повторного отображения в JSP, а не во время обработки отправленных данных в сервлете или во время < em>сохранение в БД. В JSP вы можете использовать JSTL (чтобы установить его, просто поместите jstl-1.2.jar в /WEB-INF/lib) < тег href="http://java.sun.com/products/jsp/jstl/1.1/docs/tlddocs/c/out.html" rel="noreferrer"><c:out> или fn:escapeXml для этого. Например.

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
...
<p>Welcome <c:out value="${user.name}" /></p>

и

<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %>
...
<input name="username" value="${fn:escapeXml(param.username)}">

Вот и все. Черный список не нужен. Обратите внимание, что данные, контролируемые пользователем, охватывают все данные, поступающие по HTTP-запросу: параметры запроса, тело и заголовки (!!).

Если вы HTML-экранируете его во время обработки отправленных данных и/или сохранения в БД, то все это распространяется по бизнес-коду и/или в базе данных. Это только проблемы с обслуживанием, и вы рискуете получить двойное экранирование или больше, когда делаете это в разных местах (например, & станет &amp;amp; вместо &amp;, так что конечный пользователь буквально увидит &amp; вместо & в поле зрения. Бизнес-код и БД находятся в поворот не чувствителен к XSS. Только представление. Вы должны избегать его только прямо здесь в представлении.

Смотрите также:

person BalusC    schedule 10.08.2010
comment
+1 ! Если бы мы только могли каким-то образом настроить выражение EL по умолчанию на html-экранирование, то нам не нужно было бы везде иметь много c:out :-) - person Albert Gan; 03.07.2012
comment
Ах, вы ответили об этой проблеме здесь: stackoverflow.com/questions/5887037/ - person Albert Gan; 03.07.2012
comment
@Albert: если я не ошибаюсь, вы уже используете JSF/Facelets, верно? Тогда все экранирование XSS уже сделано за вас, да. - person BalusC; 03.07.2012
comment
Вау, ты еще помнишь! Да, я работал с Facelets, но в настоящее время работаю над проектом, использующим SpringMVC и JSP в качестве представления. Итак, мой текущий вывод - c:out при отображении пользовательского ввода и EL для остальных. - person Albert Gan; 03.07.2012
comment
Что, если в выходном значении есть что-то вроде ‹font color=#FF0000›, оно будет отображаться без изменений. - person Narayana Nagireddi; 04.10.2012
comment
@Altair: используйте Jsoup#clean() для удаления потенциально вредоносного HTML из строки. См. также stackoverflow.com/questions/7722159/ - person BalusC; 04.10.2012
comment
Отличный источник, спасибо!! - person Narayana Nagireddi; 04.10.2012
comment
Но у меня также есть тег привязки с некоторым JavaScript в атрибуте value, так что я могу сделать в этом случае? - person Narayana Nagireddi; 05.10.2012
comment
Что произойдет, если у вас есть JSONP API. Вы не знаете, как ваши клиенты будут его использовать. Не лучше ли в таком случае убрать уязвимости при хранении данных? - person Alessandro Giannone; 24.03.2013
comment
У меня та же проблема, и я сомневаюсь в правильности вашего существующего ответа, так как он относится к 2009 году. Я открыл новый вопрос, не могли бы вы ответить, пожалуйста? Мой вопрос здесь - stackoverflow.com/q/63969509/1379286 - person JustCause; 20.09.2020
comment
@LemonJuice: ответ актуален и в наши дни. - person BalusC; 20.09.2020
comment
@BalusC: Круто. Так что, в принципе, наличия JSTL более чем достаточно, не так ли? Прежде чем перейти к объяснениям для аудиторов безопасности, я должен знать факты, вот почему. - person JustCause; 21.09.2020

Используйте оба. На самом деле обратитесь к такому руководству, как памятка OWASP XSS Prevention, на возможные случаи использования кодирования вывода и проверки ввода.

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

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

Взгляните на исходный код OWASP ESAPI, чтобы узнать, как работают выходные кодировщики и входные валидаторы. написано в библиотеке безопасности.

person Vineet Reynolds    schedule 21.07.2009

Я предпочитаю кодировать все небуквенно-цифровые символы как объекты числовых символов HTML. Поскольку почти, если не все атаки требуют неалфавитных символов (таких как ‹, и т. д.), это должно устранить большую часть опасного вывода.

Формат — &#N;, где N — числовое значение символа (вы можете просто привести символ к типу int и объединить его со строкой, чтобы получить десятичное значение). Например:

// java-ish pseudocode
StringBuffer safestrbuf = new StringBuffer(string.length()*4);
foreach(char c : string.split() ){  
  if( Character.isAlphaNumeric(c) ) safestrbuf.append(c);
  else safestrbuf.append(""+(int)symbol);

Вы также должны быть уверены, что кодируете непосредственно перед выводом в браузер, чтобы избежать двойного кодирования или кодирования для HTML, но с отправкой в ​​другое место.

person Community    schedule 21.07.2009
comment
Пробел не буквенно-цифровой, верно? - person Tom Hawtin - tackline; 22.07.2009
comment
Правильный. Пробел не является буквенно-цифровым и, учитывая этот очень драконовский алгоритм, будет кодироваться в . Может показаться, что в этом нет необходимости, но подумайте о случае, когда обрабатываются только известные опасные символы одинарных и двойных кавычек, если вывод построен из следующего фрагмента JSP: ‹input name=foo value=‹%= userdata %› › если бы пользователь отправил такое значение, как x onfocus=alert(1), он смог бы выполнить XSS. P.S. есть ли способ форматировать комментарии? Я пытаюсь красиво печатать, но не могу... - person ; 23.07.2009