Повторное использование значения ViewState в другом сеансе (CSRF)

Я использую * myfaces-api-2.2.3 с javax.faces.STATE_SAVING_METHOD, установленным клиентом,

Я получил следующий сценарий,

1) Пользователь X регистрируется в системе и добавляет пользователя XXX (используя jsf f: ajax action), а при проверке инструментов chorme dev вы можете видеть форму, которая представляется вместе со значением ViewState.

2) Скопируйте это значение ViewState (из chrome dev tools → network tab) → поместите его в html файл с формой (который имитирует мой оригинальный пользователь X)

3) Выход из сеанса пользователя X (сеанс недействителен во время этого процесса)

4) Войти с пользователем Y → открыть этот html файл в браузере и нажать кнопку отправки формы → вы заметите, что пользователь XXX был добавлен (несмотря на то, что Значение ViewState, которое использовалось в форме, принадлежит другому пользователю (Пользователь X).

Я думал, что значение ViewState не может быть использовано таким образом, и я думал, что он должен предотвращать подобные действия, как можно использовать одно значение ViewState в совершенно новом сеансе, который имеет собственное значение ViewState и как я могу убедиться, что пользователь не сможет повторно использовать ViewState?


Посмотрите мой другой вопрос и BalusC answer: Предотвратите CSRF в JSF2 с сохранением состояния на стороне клиента

Ответ 1

Это указано/ожидаемое поведение при сохранении состояния клиентской стороны. Состояние представления JSF не сохраняется в сеансе, но полностью в скрытом поле ввода в форме HTML на стороне клиента. Только при использовании сохранения состояния на стороне сервера состояние представления JSF будет недействительным, если оно не существует в пользовательском сеансе HTTP.

Я не вижу любым способом в MyFaces, чтобы аннулировать сохраненное состояние на стороне клиента, если оно повторно связано с "неправильным" сеансом во время постбэк. Параметр контекста org.apache.myfaces.CLIENT_VIEW_STATE_TIMEOUT близок. Вы можете установить его в то же время, что и время ожидания сеанса.

Сценарий атаки CSRF - это ИМО, немного преувеличенный. Во-первых, злоумышленник должен иметь возможность получить руку от состояния клиентской стороны. Самый простой способ - это отверстие XSS. Только JSF повсеместно предотвращает атаку XSS (если вы осторожны с escape="false"). Самый сложный способ - иметь руку всего HTML-вывода. Это можно сделать с помощью атаки "человек в середине". Только это также дает злоумышленнику весь сеансовый файл cookie, поэтому весь сценарий атаки CSRF в этом случае "излишне усложняется" для злоумышленника, так как злоумышленник может просто захватить сеанс. Лучшая защита от этого - просто использование HTTPS вместо HTTP.

Даже тогда, если злоумышленник каким-то образом получил представление о состоянии стороны на стороне клиента, злоумышленник не может делать с ним много опасных вещей без дешифрования, неэриализации и манипулирования им. MyFaces шифрует его по умолчанию в течение длительного времени (уже с раннего 2.0.x). Злоумышленник не может расшифровать его, не имея правильного ключа и, следовательно, также не манипулировать им. Это шифрование состояния просмотра на стороне клиента, кстати, становится обязательной частью спецификации JSF 2.2 (поэтому Mojarra также делает это). Этот ключ получает по умолчанию reset при перезапуске сервера приложений (и, следовательно, все состояния клиентской стороны будут аннулированы). Вы можете, если необходимо, указать фиксированный ключ, указав ниже запись среды в web.xml:

<env-entry>
    <env-entry-name>jsf.ClientSideSecretKey</env-entry-name>
    <env-entry-type>java.lang.String</env-entry-type>
    <env-entry-value>[AES key in Base64 format]</env-entry-value>
</env-entry>

Вы можете использовать эту страницу для создания случайного ключа AES в формате Base64.

Даже тогда, если злоумышленнику каким-то образом удастся расшифровать состояние представления и получить другого пользователя для его фактического представления (например, через отверстие XSS или фишинговый сайт), тогда лучше всего включить токен CSRF на основе сеанса HTTP в страницу JSF. Но также это небезопасно, если у webapp по-прежнему есть дыра XSS-атаки, или передается через HTTP вместо HTTPS.

См. также: