Статьи

Основные характеристики Spring Security 3.2.0 RC1: защита CSRF


Этот пост был написан Робом Винчем в блоге SpringSource. 

В понедельник я объявил о  выпуске Spring Security 3.2.0.RC1 . Это первая из серии блогов, состоящей из двух частей, в которой рассказывается о новых функциях Spring Security 3.2.0.RC1.

В этой первой записи я расскажу о поддержке CSRF в Spring Security. В следующем посте я рассмотрю различные заголовки безопасности, которые были добавлены.

CSRF ATTACKS

В Spring Security добавлена ​​защита от  кросс-подделки запросов (CSRF) . Отлично, но что такое CSRF-атака и как Spring Security может защитить меня от нее? Давайте рассмотрим конкретный пример, чтобы лучше понять.

Предположим, что веб-сайт вашего банка предоставляет форму, которая позволяет переводить деньги от текущего пользователя на другой банковский счет. Например, HTTP-запрос может выглядеть так:

POST /transfer HTTP/1.1
Host: bank.example.com
Cookie: JSESSIONID=randomid; Domain=bank.example.com; Secure; HttpOnly
Content-Type: application/x-www-form-urlencoded

amount=100.00&routingNumber=1234&account=9876

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

<form action="https://bank.example.com/transfer" method="post">
  <input type="hidden"
      name="amount"
      value="100.00"/>
  <input type="hidden"
      name="routingNumber"
      value="evilsRoutingNumber"/>
  <input type="hidden"
      name="account"
      value="evilsAccountNumber"/>
  <input type="submit"
      value="Win Money!'/>
</form>

Вам нравится выигрывать деньги, поэтому вы нажимаете на кнопку отправки. При этом вы непреднамеренно перевели 100 долларов злоумышленнику. Это происходит потому, что, хотя злой сайт не может видеть ваши куки, куки, связанные с вашим банком, по-прежнему отправляются вместе с запросом.

Хуже всего то, что весь этот процесс мог быть автоматизирован с использованием JavaScript. Это означает, что вам даже не нужно нажимать на кнопку. Так как же мы защищаемся от таких атак?

СИНХРОНИЗАТОР ЗНАКОМ

Проблема в том, что HTTP-запрос с веб-сайта банка и запрос с злого веб-сайта в точности совпадают. Это означает, что нет способа отклонить запросы, поступающие со злого веб-сайта, и разрешить запросы, поступающие с веб-сайта банка. Для защиты от CSRF-атак нам нужно убедиться, что в запросе есть что-то, что злой сайт не может предоставить.

Одним из решений является использование  шаблона токена синхронизатора . Это решение заключается в том, чтобы каждый запрос, помимо нашего файла cookie сеанса, требовал случайно сгенерированный токен в качестве параметра HTTP. Когда запрос отправлен, сервер должен найти ожидаемое значение параметра и сравнить его с фактическим значением в запросе. Если значения не совпадают, запрос должен завершиться неудачей.

Мы можем ослабить ожидания, требуя токен только для каждого HTTP-запроса, который обновляет состояние. Это можно сделать безопасно, поскольку та  же самая политика происхождения  гарантирует, что злой сайт не сможет прочитать ответ. Кроме того, мы не хотим включать случайный токен в HTTP GET, так как это может  привести к утечке токенов .

Давайте посмотрим, как изменится наш пример. Предположим, что случайно сгенерированный токен присутствует в параметре HTTP с именем _csrf. Например, запрос на перевод денег будет выглядеть так:

POST /transfer HTTP/1.1
Host: bank.example.com
Cookie: JSESSIONID=randomid; Domain=bank.example.com; Secure; HttpOnly
Content-Type: application/x-www-form-urlencoded

amount=100.00&routingNumber=1234&account=9876&_csrf=<secure-random>

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

ИСПОЛЬЗОВАНИЕ ПОДДЕРЖКИ CSRF SPRING SECURITY

Итак, какие шаги необходимы для использования Spring Security для защиты нашего сайта от CSRF-атак? Шаги для использования защиты CSRF Spring Security описаны ниже:

Используйте правильные HTTP-глаголы

Первый шаг к защите от CSRF-атак — убедиться, что ваш сайт использует правильные HTTP-глаголы. В частности, прежде чем поддержка CSRF в Spring Security станет полезной, вы должны быть уверены, что ваше приложение использует PATCH, POST, PUT и / или DELETE для всего, что изменяет состояние. Это не ограничение поддержки Spring Security, а общее требование правильного предотвращения CSRF.

Настройка защиты CSRF

Следующим шагом является включение защиты CSRF Spring Security в ваше приложение. Если вы используете конфигурацию XML, это можно сделать с помощью   элемента <csrf /> :

<http ...>
    ...
    <csrf />
</http>

Защита CSRF включена по умолчанию в конфигурации Java. Для любопытных, соответствующая конфигурация Java может быть замечена ниже:

@EnableWebSecurity
@Configuration
public class WebSecurityConfig extends
   WebSecurityConfigurerAdapter {

  @Override
  protected void configure(HttpSecurity http) throws Exception {
    http
      .csrf()
        .and()
      ...;
  }
}

Включить токен CSRF


RequestDataValueProcessor

Если вы используете тег Spring MVC <form: form>, CsrfToken автоматически включается для вас с помощью
CsrfRequestDataValueProcessor .

Также интересно, что как только 
проблема 7  будет решена, Thymeleaf должен иметь автоматическую интеграцию.

Последний шаг — убедиться, что вы включили токен CSRF во все методы PATCH, POST, PUT и DELETE. Это можно сделать с помощью атрибута запроса _csrf для получения текущего  CsrfToken . Пример выполнения этого с JSP показан ниже:

<c:url var="logoutUrl" value="/logout"/>
<form action="${logoutUrl}"
    method="post">
  <input type="submit"
    value="Log out" />
  <input type="hidden"
    name="${_csrf.parameterName}"
    value="${_csrf.token}"/>
</form>

Предостережения CSRF

Есть несколько предостережений при реализации CSRF.

Таймауты


CSRF в

файлах cookie
Можно спросить, почему CsrfToken не сохраняется в файле cookie. Это связано с тем, что существуют известные эксплойты, в которых заголовки (например, установка файлов cookie) могут быть установлены другим доменом. Другим недостатком является то, что, удаляя состояние (то есть тайм-аут), вы теряете возможность принудительно завершать токен, если что-то было взломано.

Одна из проблем заключается в том, что ожидаемый токен CSRF хранится в HttpSession, поэтому по истечении срока HttpSession настроенный AccessDeniedHandler получит исключение InvalidCsrfTokenException. Если вы используете AccessDeniedHandler по умолчанию, браузер получит HTTP 403 и отобразит плохое сообщение об ошибке.

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

В качестве альтернативы, указание пользовательского AccessDeniedHandler позволяет вам обрабатывать InvalidCsrfTokenException так, как вам нравится. Для примера того, как настроить AccessDeniedHandler, обратитесь к предоставленным ссылкам для  конфигурации xml  и  Java .

Вход в систему

Для защиты от  подделки запросов  на вход в систему следует также защищать форму входа в систему от CSRF-атак. Поскольку CsrfToken хранится в HttpSession, это означает, что HttpSession будет создан немедленно. Хотя это звучит плохо в архитектуре RESTful / без состояний, реальность такова, что состояние необходимо для обеспечения практической безопасности. Без государства мы ничего не можем сделать, если токен скомпрометирован. Практически говоря, токен CSRF довольно мал по размеру и должен оказывать незначительное влияние на нашу архитектуру.

Выйти

Добавление CSRF обновит LogoutFilter для использования только HTTP POST. Это гарантирует, что для выхода требуется токен CSRF и что злонамеренный пользователь не сможет принудительно выйти из системы ваших пользователей.

Одним из подходов является использование формы для выхода из системы. Если вы действительно хотите ссылку, вы можете использовать JavaScript, чтобы ссылка выполняла POST (то есть, возможно, в скрытой форме). Для браузеров с отключенным JavaScript вы можете по желанию получить ссылку на страницу подтверждения выхода из системы, которая будет выполнять POST.

HiddenHttpMethodFilter

HiddenHttpMethodFilter должен находиться перед фильтром Spring Security. В целом это действительно так, но это может иметь дополнительные последствия при защите от CSRF-атак.

Обратите внимание, что HiddenHttpMethodFilter переопределяет только HTTP-метод на POST, так что это вряд ли вызовет какие-либо реальные проблемы. Тем не менее, по-прежнему рекомендуется размещать его перед фильтрами Spring Security.

Переопределяющие значения по умолчанию

Цель Spring Security — предоставить настройки по умолчанию, которые защищают ваших пользователей от эксплойтов. Это не означает, что вы вынуждены принять все его значения по умолчанию.

Например, вы можете предоставить пользовательский  CsrfTokenRepository  для переопределения способа хранения CsrfToken.

Вы также можете указать пользовательский  RequestMatcher,  чтобы определить, какие запросы защищены CSRF (т. Е., Возможно, вам все равно, если используется выход из системы). Короче говоря, если CSRF-защита Spring Security работает не так, как вы этого хотите, вы можете настроить ее поведение.

ВЫВОД

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

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