Как я могу предотвратить атаки XSS в веб-приложении JSP / Servlet?
Предотвращение XSS в веб-приложении JSP / Servlet
Ответы (9)
XSS можно предотвратить в JSP, используя JSTL _ 1_ тег или _ 2_ Функция EL при (повторном) отображении ввода, управляемого пользователем. Сюда входят параметры запроса, заголовки, файлы cookie, URL, тело и т. Д. Все, что вы извлекаете из объекта запроса. Кроме того, во время повторного отображения необходимо экранировать управляемый пользователем ввод из предыдущих запросов, который хранится в базе данных.
Например:
<p><c:out value="${bean.userControlledValue}"></p>
<p><input name="foo" value="${fn:escapeXml(param.foo)}"></p>
Это приведет к экранированию символов, которые могут искажать отображаемый HTML, например <
, >
, "
, '
и &
, в HTML / XML. объекты, такие как <
, >
, "
, '
и &
.
Обратите внимание, что вам не нужно экранировать их в коде Java (сервлета), поскольку там они безвредны. Некоторые могут избежать их во время обработки запроса (как вы делаете в сервлете или фильтре) вместо обработки ответа (как в JSP), но таким образом вы можете рискнуть что данные излишне экранированы с двойным экранированием (например, &
становится &amp;
вместо &
, и в конечном итоге конечный пользователь увидит &
представление), или что данные, хранящиеся в БД, становятся непереносимыми (например, при экспорте данных в JSON, CSV, XLS, PDF, и т. д., который вообще не требует экранирования HTML). Вы также потеряете социальный контроль, потому что больше не знаете, что на самом деле ввел пользователь. Как администратор сайта, вы бы действительно хотели знать, какие пользователи / IP-адреса пытаются выполнить XSS, чтобы вы могли легко отслеживать их и предпринять соответствующие действия. Экранирование во время обработки запроса должно использоваться только и только в качестве последнего средства, когда вам действительно нужно как можно быстрее исправить крушение поезда плохо разработанного устаревшего веб-приложения. Тем не менее, вы должны в конечном итоге переписать файлы JSP, чтобы они стали безопасными для XSS.
Если вы хотите повторно отображать ввод, управляемый пользователем, как HTML, в котором вы хотите разрешить только определенное подмножество HTML-тегов, например <b>
, <i>
, <u>
и т. Д., То вам необходимо очистить ввод с помощью белого списка. Для этого вы можете использовать анализатор HTML, например Jsoup. Но гораздо лучше ввести удобный для человека язык разметки, такой как Markdown (также используется здесь, в Stack Overflow). Затем вы можете использовать для этого парсер Markdown, например CommonMark. Он также имеет встроенные возможности очистки HTML. См. Также Markdown или HTML.
Единственная проблема на стороне сервера в отношении баз данных - это SQL-инъекция. Вам необходимо убедиться, что вы никогда не объединяете строки, управляемые пользователем, прямо в запросе SQL или JPQL и полностью используете параметризованные запросы. В терминах JDBC это означает, что вы должны использовать PreparedStatement
вместо Statement
. В терминах JPA используйте Query
.
Альтернативой может быть переход с JSP / сервлета на структуру Java EE MVC JSF. Он имеет встроенную защиту от XSS (и CSRF!) Повсюду. См. Также Предотвращение атак CSRF, XSS и SQL-инъекций в JSF а>.
"SELECT ... WHERE SOMEVAL = " + someval
вместо использования параметризованных запросов, как вы показали. Ни один ORM не может защитить от подобных ошибок разработчика.
- person BalusC; 11.02.2012
<div><c:out value="${htmlContent}" escapeXml="false" /></div>
здесь htmlContent
value - это что-то вроде <span><h1>Hi</h1></span>
(это значение, поступающее из базы данных), теперь, если я удалю escapeXml="false"
из c:out
, тогда он отобразится как на странице, тогда если продолжите escapeXml="false"
его синтаксический анализ объект dom правильно, но когда мой htmlContent имеет некоторый код сценария, возникает проблема xss.
- person Venkaiah Yepuri; 04.01.2017
htmlContent
равно <span><h1><script>alert("Hi");</script></h1></span>
, тогда, если я использую <c:out value="${htmlContent}" escapeXml="false" /></div>
в jsp, тогда в браузере пользователь получит окно предупреждения, поэтому это может привести к проблеме XSS. Пожалуйста, посоветуйте мне, что я могу сделать в этой ситуации.
- person Venkaiah Yepuri; 04.01.2017
How-to-prevent-xss спрашивали несколько раз. Вы найдете много информации в StackOverflow. Кроме того, на веб-сайте OWASP есть шпаргалка по предотвращению XSS-атак, которую вам следует изучить .
Что касается используемых библиотек, библиотека ESAPI OWASP имеет разновидность java. . Тебе стоит попробовать это. Кроме того, каждый фреймворк, который вы используете, имеет некоторую защиту от XSS. Опять же, на веб-сайте OWASP есть информация о наиболее популярных фреймворках, поэтому я бы порекомендовал пройтись по их сайту.
Мне очень повезло с OWASP Anti-Samy и советником AspectJ на всех моих контроллерах Spring, который блокирует проникновение XSS.
public class UserInputSanitizer {
private static Policy policy;
private static AntiSamy antiSamy;
private static AntiSamy getAntiSamy() throws PolicyException {
if (antiSamy == null) {
policy = getPolicy("evocatus-default");
antiSamy = new AntiSamy();
}
return antiSamy;
}
public static String sanitize(String input) {
CleanResults cr;
try {
cr = getAntiSamy().scan(input, policy);
} catch (Exception e) {
throw new RuntimeException(e);
}
return cr.getCleanHTML();
}
private static Policy getPolicy(String name) throws PolicyException {
Policy policy =
Policy.getInstance(Policy.class.getResourceAsStream("/META-INF/antisamy/" + name + ".xml"));
return policy;
}
}
Вы можете получить советник AspectJ из этого сообщения stackoverflow < / а>
Я думаю, что это лучший подход, чем c: out, особенно если вы много используете javascript.
Для управления XSS требуется несколько проверок данных со стороны клиента.
- Проверка ввода (проверка формы) на стороне сервера. Есть несколько способов добиться этого. Вы можете попробовать проверку bean-компонентов JSR 303 (hibernate validator ) или Платформа проверки ввода ESAPI. Хотя я сам (пока) не пробовал, есть аннотация, которая проверяет безопасный HTML (@SafeHtml). Фактически вы можете использовать валидатор Hibernate с Spring MVC для проверки bean-компонентов -> Ссылка
- Экранирование запросов URL. Для всех ваших HTTP-запросов используйте какой-то фильтр XSS. Я использовал следующее для нашего веб-приложения, и оно заботится об очистке запроса URL-адреса HTTP: http://www.servletsuite.com/servlets/xssflt.htm
- Экранирование данных / HTML, возвращенных клиенту (см. объяснение @BalusC выше).
Я бы посоветовал регулярно тестировать уязвимости с помощью автоматизированного инструмента и исправлять все, что он находит. Намного проще предложить библиотеку для устранения конкретной уязвимости, чем для всех XSS-атак в целом.
Skipfish - это инструмент с открытым исходным кодом от Google, который я исследовал: он находит довольно много всего, и, кажется, стоит использовать.
Нет простого готового решения против XSS. OWASP ESAPI API имеет некоторую поддержку экранирования, что очень полезно, и у них есть библиотеки тегов.
Мой подход заключался в том, чтобы расширить теги stuts 2 следующими способами.
- Измените тег s: property, чтобы он мог принимать дополнительные атрибуты, указывающие, какой тип экранирования требуется (escapeHtmlAttribute = "true" и т. Д.). Это включает в себя создание новых классов Property и PropertyTag. Класс Property использует OWASP ESAPI api для экранирования.
- Измените шаблоны freemarker, чтобы использовать новую версию s: property, и установите экранирование.
Если вы не хотели изменять классы на шаге 1, можно было бы импортировать теги ESAPI в шаблоны freemarker и при необходимости уйти. Затем, если вам нужно использовать тег s: property в вашем JSP, оберните его тегом и ESAPI.
Я написал здесь более подробное объяснение.
http://www.nutshellsoftware.org/software/securing-struts-2-using-esapi-part-1-securing-outputs/
Я согласен, что экранирование входных данных не идеально.
Мое личное мнение таково, что вам следует избегать использования страниц JSP / ASP / PHP / etc. Вместо этого выводите в API, похожий на SAX (предназначенный только для вызова, а не для обработки). Таким образом, создается единственный слой, который должен создавать хорошо сформированный вывод.
Если вы хотите автоматически экранировать все переменные JSP без явного переноса каждой переменной, вы можете использовать преобразователь EL , как подробно описано здесь с полным исходным кодом и примером (JSP 2.0 или новее), и обсуждается более подробно здесь:
Например, при использовании вышеупомянутого преобразователя EL ваш код JSP останется таким, но каждая переменная будет автоматически экранирована преобразователем
...
<c:forEach items="${orders}" var="item">
<p>${item.name}</p>
<p>${item.price}</p>
<p>${item.description}</p>
</c:forEach>
...
Если вы хотите принудительно экранировать по умолчанию в Spring, вы также можете рассмотреть это, но это не экранирует выражения EL, а просто вывод тегов, я думаю:
http://forum.springsource.org/showthread.php?61418-Spring-cross-site-scripting&p=205646#post205646
Примечание. Другой подход к экранированию EL, использующий преобразования XSL для предварительной обработки файлов JSP, можно найти здесь:
http://therning.org/niklas/2007/09/preprocessing-jsp-files-to-automatically-escape-el-expressions/
<enhance:out escapeXml="false">
, как подробно описано в статье.
- person Brad Parks; 08.05.2020
Если вы хотите убедиться, что ваш $
оператор не пострадал от взлома XSS, вы можете реализовать ServletContextListener
и провести там некоторые проверки.
Полное решение по адресу: http://pukkaone.github.io/2011/01/03/jsp-cross-site-scripting-elresolver.html.
@WebListener
public class EscapeXmlELResolverListener implements ServletContextListener {
private static final Logger LOG = LoggerFactory.getLogger(EscapeXmlELResolverListener.class);
@Override
public void contextInitialized(ServletContextEvent event) {
LOG.info("EscapeXmlELResolverListener initialized ...");
JspFactory.getDefaultFactory()
.getJspApplicationContext(event.getServletContext())
.addELResolver(new EscapeXmlELResolver());
}
@Override
public void contextDestroyed(ServletContextEvent event) {
LOG.info("EscapeXmlELResolverListener destroyed");
}
/**
* {@link ELResolver} which escapes XML in String values.
*/
public class EscapeXmlELResolver extends ELResolver {
private ThreadLocal<Boolean> excludeMe = new ThreadLocal<Boolean>() {
@Override
protected Boolean initialValue() {
return Boolean.FALSE;
}
};
@Override
public Object getValue(ELContext context, Object base, Object property) {
try {
if (excludeMe.get()) {
return null;
}
// This resolver is in the original resolver chain. To prevent
// infinite recursion, set a flag to prevent this resolver from
// invoking the original resolver chain again when its turn in the
// chain comes around.
excludeMe.set(Boolean.TRUE);
Object value = context.getELResolver().getValue(
context, base, property);
if (value instanceof String) {
value = StringEscapeUtils.escapeHtml4((String) value);
}
return value;
} finally {
excludeMe.remove();
}
}
@Override
public Class<?> getCommonPropertyType(ELContext context, Object base) {
return null;
}
@Override
public Iterator<FeatureDescriptor> getFeatureDescriptors(ELContext context, Object base){
return null;
}
@Override
public Class<?> getType(ELContext context, Object base, Object property) {
return null;
}
@Override
public boolean isReadOnly(ELContext context, Object base, Object property) {
return true;
}
@Override
public void setValue(ELContext context, Object base, Object property, Object value){
throw new UnsupportedOperationException();
}
}
}
Опять же: это только охраняет $
. См. Также другие ответы.