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
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 в другом браузере, не входя в приложение. Когда вы попытаетесь отправить форму, мы получим страницу:
Наш запрос был отклонен, потому что мы отправили запрос без токена 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, поэтому его будет легко импортировать и запускать как есть.