Предотвращение атак CSRF, XSS и SQL-инъекций в JSF

У меня есть веб-приложение, построенное на JSF с MySQL в качестве БД. Я уже реализовал код для предотвращения CSRF в моем приложении.

Теперь, так как моя базовая структура - JSF, я думаю, мне не нужно обрабатывать XSS-атаку, так как она уже обрабатывается UIComponent, Я не использую JavaScript ни на одной из страниц просмотра. Даже если я использую, действительно ли мне нужно реализовать код для предотвращения атак XSS?

Для БД мы используем подготовленные операторы и хранимые процедуры во всех взаимодействиях БД.

Есть ли что-нибудь еще, что нужно сделать для предотвращения этих 3 распространенных атак? Я уже был через сайт OWASP и их шпаргалки.

Нужно ли мне позаботиться о любых других потенциальных векторах атаки?

2 ответа

Решение

XSS

JSF имеет встроенную функцию предотвращения XSS. Вы можете безопасно повторно отобразить все контролируемые пользователем данные (заголовки запросов (включая файлы cookie!), Параметры запросов (также те, которые сохраняются в БД!) И тела запросов (загруженные текстовые файлы и т. Д.)) С использованием любого компонента JSF.

<h:outputText value="#{user.name}" />
<h:outputText value="#{user.name}" escape="true" />
<h:inputText value="#{user.name}" />
etc...

Обратите внимание, что когда вы используете JSF 2.0 на Facelets, вы можете использовать EL в тексте шаблона следующим образом:

<p>Welcome, #{user.name}</p>

Это также будет неявно избежать. Вам не обязательно нужно <h:outputText> Вот.

Только когда вы явно не экранируете контролируемый пользователем ввод с помощью escape="false":

<h:outputText value="#{user.name}" escape="false" />

тогда у вас есть потенциальная дыра в атаке XSS!

Если вы хотите снова отобразить пользовательский ввод в виде HTML, в котором вы хотите разрешить только определенное подмножество HTML-тегов, например <b>, <i>, <u> и т. д., то вам нужно санировать ввод с помощью белого списка. HTML-парсер Jsoup очень помогает в этом.

itemLabelEscaped ошибка в Моджарре < 2.2.6

Более старые версии Mojarra до 2.2.6 имели ошибку, при которой <f:selectItems itemLabel> неправильно отображает ярлык как неэкранированный, если List<T> с помощью <f:selectItems var> вместо List<SelectItem> или же SelectItem[] в качестве значения ( выпуск 3143). Другими словами, если вы повторно отображаете данные, контролируемые пользователем, в качестве меток элементов через List<T> тогда у вас есть потенциальная дыра в XSS. Если обновление хотя бы до Mojarra 2.2.6 не вариант, вам нужно явно установить itemLabelEscaped приписывать true чтобы предотвратить это.

<f:selectItems value="#{bean.entities}" var="entity" itemValue="#{entity}"
    itemLabel="#{entity.someUserControlledProperty}" itemLabelEscaped="true" />

CSRF

JSF 2.x уже имеет встроенную функцию предотвращения CSRF javax.faces.ViewState скрытое поле в форме при сохранении состояния сервера. В JSF 1.x это значение было довольно слабым и слишком легко предсказуемым (фактически оно никогда не предназначалось для предотвращения CSRF). В JSF 2.0 это было улучшено за счет использования длинного и сильного автоматически сгенерированного значения вместо довольно предсказуемого значения последовательности и, таким образом, превращения его в надежное предотвращение CSRF.

В JSF 2.2 это еще более улучшилось, сделав его обязательной частью спецификации JSF вместе с настраиваемым ключом AES для шифрования состояния на стороне клиента, если включено сохранение состояния на стороне клиента. См. Также выпуск 869 спецификации JSF и Повторное использование значения ViewState в другом сеансе (CSRF). Новое в JSF 2.2 - защита CSRF от запросов GET <protected-views>,

Только когда вы используете представления без состояния, как в <f:view transient="true"> или в приложении где-то есть дыра для атаки XSS, тогда у вас есть потенциальная дыра для атаки CSRF.


SQL-инъекция

Это не является обязанностью JSF. Как это предотвратить, зависит от используемого вами API персистентности (необработанный JDBC, современный JPA или хороший старый Hibernate), но все сводится к тому, что вам никогда не следует объединять вводимые пользователем данные в строки SQL, например, так

String sql = "SELECT * FROM user WHERE username = '" + username + "' AND password = md5(" + password + ")";
String jpql = "SELECT u FROM User u WHERE u.username = '" + username + "' AND u.password = md5('" + password + "')";

Представьте, что произойдет, если конечный пользователь выберет следующее имя:

x'; DROP TABLE user; --

Вы должны всегда использовать параметризованные запросы, где это применимо.

String sql = "SELECT * FROM user WHERE username = ? AND password = md5(?)";
String jpql = "SELECT u FROM User u WHERE u.username = ?1 AND u.password = md5(?2)";

В простом JDBC вам нужно использовать PreparedStatement заполнить значения параметров и в JPA (и Hibernate), Query объект также предлагает сеттеры для этого.

Я не использую JavaScript ни на одной из страниц просмотра. Даже если я использую, мне действительно нужно реализовать код, чтобы обойти XSS Attack.

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

В любое время вы делаете что-то вроде

response.write("<b>" + x + "</b>")

где злоумышленник может вызвать x чтобы содержать HTML, который содержит JavaScript, то вы уязвимы для XSS.

Решение обычно состоит в том, чтобы не писать большие объемы кода. Как правило, решение заключается в кодировании $x и любые другие значения, контролируемые злоумышленником, прежде чем включать их в генерируемый вами HTML.

response.write("<b>" + escapePlainTextToHtml(x) + "</b>")

Фильтрация или дезинфекция входных данных может помочь обеспечить дополнительный уровень защиты.

<shameless-plug>

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

Закрытие шаблона является одним из таких вариантов для Java.

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

РЕДАКТИРОВАТЬ

Поскольку вы используете JSF, вы должны прочитать о смягчении XSS в JSF:

Escape выходной текст

<h:outputText/> а также <h:outputLabel/> по умолчанию атрибут escape имеет значение True. Используя этот тег для отображения выходных данных, вы можете уменьшить большинство уязвимостей XSS.

SeamTextParser и<s:formattedText/>

Если вы хотите, чтобы пользователи могли использовать некоторые основные HTML-теги для настройки своих входных данных, JBoss Seam предоставляет <s:formattedText/> тег, который позволяет некоторые основные HTML-теги и стили, указанные пользователями.

Когда используешь <h:outputText escape="false">с неэкранированными значениями (например, исходящими из текстовых редакторов html) вы открыты для неприятных атак XSS. В таких случаях я использую конвертер JSF, который использует Jsoup для удаления javascript из текста, оставляя HTML нетронутым. Конвертер также можно использовать для дезинфекции пользовательского ввода. Вы можете использовать это так:

<h:outputText value="{bean.value}" escape="false" converter="htmlSanitizingConverter"/>

И сам конвертер:

/**
 * Prevents from XSS attack if output text is not escaped.
 */
@FacesConverter("htmlSanitizingConverter")
public class HtmlSanitizingConverter implements Converter {

    private static final Whitelist JSOUP_WHITELIST = Whitelist.relaxed()
            .preserveRelativeLinks(true)
            .addAttributes(":all","style");
            /*
             Optionally - add support for hyperlinks and base64 encoded images.
            .addTags("img")
            .addAttributes("img", "height", "src", "width")
            .addAttributes("a", "href")
            .addProtocols("img", "src", "http", "https", "data");
            */

    @Override
    public Object getAsObject(FacesContext context, UIComponent component, String submittedValue) {
        return (submittedValue != null) ? Jsoup.clean(submittedValue, JSOUP_WHITELIST) : null;
    }

    @Override
    public String getAsString(FacesContext context, UIComponent component, Object value) {
        return (value != null) ? Jsoup.clean(value.toString(), JSOUP_WHITELIST) : "";
    }

}

Примечание. Когда вы используете JSF с PrimeFaces, остерегайтесь <p:textEditor>- более старые версии (до 6.2) по умолчанию не очищали вводимые пользователем данные.

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