CSRF Защита с помощью Spring MVC и Thymeleaf

CSRF защита с помощью Spring MVC и Thymeleaf

1. Вступление

Thymeleaf - это шаблонизатор Java для обработки и создания HTML, XML, JavaScript, CSS и открытого текста. Чтобы познакомиться с Thymeleaf и Spring, посмотритеthis writeup.

В этой статье мы обсудим, как использоватьprevent Cross-Site Request Forgery (CSRF) attacks в Spring MVC с приложением Thymeleaf. Чтобы быть более конкретным, мы будем тестировать CSRF-атаку для метода HTTP POST.

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

2. Maven Зависимости

Во-первых, давайте посмотрим конфигурации, необходимые для интеграции Thymeleaf с Spring. Библиотекаthymeleaf-spring требуется в наших зависимостях:


    org.thymeleaf
    thymeleaf
    3.0.9.RELEASE


    org.thymeleaf
    thymeleaf-spring4
    3.0.9.RELEASE

Обратите внимание, что для проекта Spring 4 библиотекаthymeleaf-spring4 должна использоваться вместоthymeleaf-spring5. Последнюю версию зависимостей можно найтиhere.

Кроме того, чтобы использовать Spring Security, нам нужно добавить следующие зависимости:


    org.springframework.security
    spring-security-web
    5.0.6.RELEASE


    org.springframework.security
    spring-security-config
    5.0.6.RELEASE

Доступны последние версии двух библиотек, связанных с Spring Security:here иhere.

3. Конфигурация Java

В дополнение к конфигурации Thymeleaf, охватываемойhere, нам нужно добавить конфигурацию для Spring Security. Для этого нам нужно создать класс:

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)
public class WebMVCSecurity extends WebSecurityConfigurerAdapter {

    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
          .withUser("user1").password("{noop}user1Pass")
          .authorities("ROLE_USER");
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/resources/**");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
          .authorizeRequests()
          .anyRequest()
          .authenticated()
          .and()
          .httpBasic();
    }
}

Дополнительные сведения и описание конфигурации безопасности см. В серииSecurity with Spring.

CSRF protection is enabled by default with Java configuration. Чтобы отключить эту полезную функцию, нам нужно добавить это в методconfigure(…):

.csrf().disable()

В конфигурации XML нам нужно указать защиту CSRF вручную, иначе она не будет работать:


    

    

Также обратите внимание, что если мы используем страницу входа с формой входа, нам необходимо всегда включать токен CSRF в форму входа в качестве скрытого параметра вручную в коде:

Для остальных форм токен CSRF будет автоматически добавлен в формы со скрытым вводом:


4. Конфигурация представлений

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




Add Student


    

Add Student

В этом представлении мы добавляем студента в список, предоставляяid,name,gender иpercentage (необязательно, как указано в проверке формы). Прежде чем мы сможем выполнить эту форму, нам нужно предоставитьuser иpassword, чтобы аутентифицировать нас в веб-приложении.

4.1. Тестирование CSRF-атак браузера

Теперь мы переходим ко второму представлению HTML. Цель этого состоит в том, чтобы попытаться выполнить CSRF-атаку:




    


Мы знаем, что URL-адрес действия -http://localhost:8080/spring-thymeleaf/saveStudent. Хакер хочет получить доступ к этой странице, чтобы выполнить атаку.

Для тестирования откройте файл HTML в другом браузере, не входя в приложение. Когда вы попытаетесь отправить форму, мы получим страницу:

image

 

Наш запрос был отклонен, потому что мы отправили запрос без токена CSRF.

Обратите внимание, что HTTP-сессия используется для хранения токена CSRF. Когда запрос отправляется, Spring сравнивает сгенерированный токен с токеном, сохраненным в сеансе, чтобы подтвердить, что пользователь не взломан.

4.2. Тестирование атак JUnit CSRF

Если вы не хотите тестировать CSRF-атаку с помощью браузера, вы также можете сделать это с помощью быстрого интеграционного теста; давайте начнем с конфигурации Spring для этого теста:

@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration(classes = {
  WebApp.class, WebMVCConfig.class, WebMVCSecurity.class, InitSecurity.class })
public class CsrfEnabledIntegrationTest {

    // configuration

}

И перейдем к реальным тестам:

@Test
public void addStudentWithoutCSRF() throws Exception {
    mockMvc.perform(post("/saveStudent").contentType(MediaType.APPLICATION_JSON)
      .param("id", "1234567").param("name", "Joe").param("gender", "M")
      .with(testUser())).andExpect(status().isForbidden());
}

@Test
public void addStudentWithCSRF() throws Exception {
    mockMvc.perform(post("/saveStudent").contentType(MediaType.APPLICATION_JSON)
      .param("id", "1234567").param("name", "Joe").param("gender", "M")
      .with(testUser()).with(csrf())).andExpect(status().isOk());
}

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

5. Заключение

В этой статье мы обсудили, как предотвратить CSRF-атаки с помощью Spring Security и Thymeleaf framework.

Полную реализацию этого руководства можно найти вthe GitHub project - это проект на основе Eclipse, поэтому его будет легко импортировать и запускать как есть.