1. 소개

Thymeleaf 는 HTML, XML, JavaScript, CSS 및 일반 텍스트를 처리하고 생성하기위한 Java 템플릿 엔진입니다. Thymeleaf 및 Spring에 대한 소개는 이 글을 참조하십시오 .

이 기사에서는 Thymeleaf 애플리케이션을 사용하여 Spring MVC에서 CSRF (Cross-Site Request Forgery) 공격방지 하는 방법에 대해 설명 합니다. 보다 구체적으로 HTTP POST 방법에 대한 CSRF 공격을 테스트합니다.

CSRF는 최종 사용자가 현재 인증 된 웹 애플리케이션에서 원치 않는 작업을 실행하도록하는 공격입니다.

2. Maven 의존성

먼저 Thymeleaf를 Spring과 통합하는 데 필요한 구성을 살펴 보겠습니다. thymeleaf 스프링 라이브러리는 우리의 의존성이 필요합니다 :

<dependency>
    <groupId>org.thymeleaf</groupId>
    <artifactId>thymeleaf</artifactId>
    <version>3.0.11.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.thymeleaf</groupId>
    <artifactId>thymeleaf-spring5</artifactId>
    <version>3.0.11.RELEASE</version>
</dependency>

스프링 4 프로젝트는, 그 주 thymeleaf - spring4의  라이브러리는 대신 사용해야합니다 thymeleaf-spring5 . 최신 버전의 의존성은 여기 에서 찾을 수 있습니다 .

또한 Spring Security를 ​​사용하려면 다음 의존성을 추가해야합니다.

<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-web</artifactId>
    <version>5.2.3.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-config</artifactId>
    <version>5.2.3.RELEASE</version>
</dependency>

두 개의 Spring Security 관련 라이브러리의 최신 버전은 여기여기에서 사용할 수 있습니다 .

3. 자바 구성

여기 에서 다루는 Thymeleaf 구성 외에도 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 구성에 대한 자세한 내용과 설명은 Security with Spring 시리즈를 참조하십시오 .

CSRF 보호는 Java 구성에서 기본적으로 활성화됩니다. 이 유용한 기능을 비활성화하려면 configure (…) 메서드에 다음 을 추가해야합니다 .

.csrf().disable()

XML 구성에서 CSRF 보호를 수동으로 지정해야합니다. 그렇지 않으면 작동하지 않습니다.

<security:http 
  auto-config="true"
  disable-url-rewriting="true" 
  use-expressions="true">
    <security:csrf />
     
    <!-- Remaining configuration ... -->
</security:http>

또한 로그인 양식과 함께 로그인 페이지를 사용하는 경우 항상 로그인 양식에 CSRF 토큰을 코드에서 수동으로 숨겨진 매개 변수로 포함해야합니다.

<input 
  type="hidden" 
  th:name="${_csrf.parameterName}" 
  th:value="${_csrf.token}" />

나머지 양식의 경우 CSRF 토큰이 숨겨진 입력이있는 양식에 자동으로 추가됩니다.

<input 
  type="hidden" 
  name="_csrf"
  value="32e9ae18-76b9-4330-a8b6-08721283d048" /> 
<!-- Example token -->

4.보기 구성

양식 작업 및 테스트 절차 생성을 사용하여 HTML 파일의 주요 부분으로 진행하겠습니다. 첫 번째보기에서 새 학생을 List에 추가하려고합니다.

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
	xmlns:th="http://www.thymeleaf.org">
<head>
<title>Add Student</title>
</head>
<body>
    <h1>Add Student</h1>
        <form action="#" th:action="@{/saveStudent}" th:object="${student}"
          method="post">
            <ul>
                <li th:errors="*{id}" />
                <li th:errors="*{name}" />
                <li th:errors="*{gender}" />
                <li th:errors="*{percentage}" />
            </ul>
    <!-- Remaining part of HTML -->
    </form>
</body>
</html>

이보기에서는 id , name , 성별백분율 을 제공하여 List에 학생을 추가합니다 (선택적으로 양식 유효성 검사에 명시된대로). 이 양식을 실행하기 전에 웹 애플리케이션에서 인증 하기 위해 userpassword 를 제공해야 합니다.

4.1. 브라우저 CSRF 공격 테스트

이제 두 번째 HTML보기로 진행합니다. 그 목적은 CSRF 공격을 시도하는 것입니다.

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
</head>
<body>
<form action="http://localhost:8080/spring-thymeleaf/saveStudent" method="post">
    <input type="hidden" name="payload" value="CSRF attack!"/>
    <input type="submit" />
</form>
</body>
</html>

작업 URL이 http : // localhost : 8080 / spring-thymeleaf / saveStudent라는 것을 알고 있습니다. 해커는 공격을 수행하기 위해이 페이지에 액세스하려고합니다.

테스트하려면 애플리케이션에 로그인하지 않고 다른 브라우저에서 HTML 파일을 엽니 다. 양식을 제출하려고하면 다음 페이지를 받게됩니다.

 

CSRF 토큰없이 요청을 보냈기 때문에 요청이 거부되었습니다.

CSRF 토큰을 저장하기 위해 HTTP 세션이 사용됩니다. 요청이 전송되면 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. 결론

이 기사에서는 Spring Security 및 Thymeleaf 프레임 워크를 사용하여 CSRF 공격을 방지하는 방법에 대해 논의했습니다.

이 예제의 전체 구현은 GitHub 프로젝트 에서 찾을 수 있습니다 .