Как я могу запретить JSF 2.2 принимать ViewState из другого сеанса?

Я использую JSF 2.2 (Glassfish 4.1). Наше веб-приложение имеет Primefaces 6.0 и Omnifaces 2.6.9 в качестве зависимостей. Состояние JSF хранится на сервере. В качестве примера скажем, что у меня есть эта форма, где userModel - это javax.faces.view.ViewScoped bean.

<h:form id="user">
    <p:inputText id="name" value="#{userModel.name}"/>
    <p:inputText id="pass" value="#{userModel.pass}"/>
    <p:commandButton id="create" value="#{msgs.lbl_add}" action="#{userModel.addUser()}"/>
</h:form>

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

<!DOCTYPE html>
<html>
    <body>
        <form action="http://appserver:8080/myapp/users.jsf" method="POST">
            <input type="hidden" name="javax.faces.source" value="user:create"/>
            <input type="hidden" name="user:create" value="user:create"/>
            <input type="hidden" name="user" value="user"/>
            <div>
                <input type="text" name="user:name" value="FAKEUSER"/>
                <input type="text" name="user:pass" value="FAKEPASSWORD"/>
                <input type="text" name="javax.faces.ViewState" value="1185295409278172717:-3206872038807094332"/>
            </div>
            <input type="submit" name="submit" value="Create User"/>
        </form>
    </body>
</html>

Я читал на SO, что ViewState - это JSF-способ предотвращения CSRF. Но в нашем веб-приложении возможен следующий сценарий (с протоколом HTTP, если это имеет значение).

  1. Злоумышленник посещает страницу входа в наше приложение, чтобы найти допустимый ViewState в исходном коде своей страницы.
  2. Злоумышленник подготавливает HTML-файл, упомянутый выше, со своим ViewState и отправляет жертве.
  3. Жертва открывает файл HTML в браузере и отправляет (из локальной файловой системы, например, file:///C:/..., или размещенной на локальном веб-сервере)
  4. Пользователь создан.

Вывод состоит в том, что наше веб-приложение/JSF в этом сценарии не проверяет, принадлежит ли полученное ViewState сеансу, идентифицированному JSESSIONID.

Разве это не уязвимость? Как я могу этого избежать?


person FuryFart    schedule 11.02.2021    source источник


Ответы (1)


В нашем случае это была ошибка в нашем приложении. Мы также используем библиотеку Deltaspike и зарегистрировали класс Handle-All-Exceptions в нашем приложении.

import org.apache.deltaspike.core.api.exception.control.ExceptionHandler;
import org.apache.deltaspike.core.api.exception.control.Handles;
import org.apache.deltaspike.core.api.exception.control.event.ExceptionEvent;

@ExceptionHandler
public class ExceptionDispatcher {

    public void processException(@Handles ExceptionEvent<Throwable> evt) {
        // Handle exception by just logging
    }
}

Это также обработало javax.faces.application.ViewExpiredException, которые возникают, если JSF находит недопустимое ViewState. В итоге запрос нормально обработался.

Лучшая реализация перенаправит на страницу с ошибкой и сделает сеанс недействительным.

person FuryFart    schedule 12.02.2021