Mustache CSRF 적용하기

더 이상의 CSRF disable은 NO!

보통 스프링 시큐리티 설명을 위한 글들을 보면 Config 코드에 다음과 같이 작성된 코드를 많이 볼 수 있다.

http.csrf().disable().build();
// 혹은
http.csrf(CsrfConfigurer::disable)

코드만 봐도 알겠지만, 이는 HttpSecurty에서 CSRF 보안을 사용하지 않도록 설정하는 것이다. 물론 예제나 테스트를 위한 프로젝트에서는 꺼도 상관없겠지만, 실제로 서비스를 운영할 때는 끄지 않는 것이 좋다.

☝️
CSRF 보안이 항상 필수적이지는 않다. 스프링 시큐리티 문서를 보면 'non-browser clients' 만을 위한 서비스라면 CSRF를 disable 해도 상관없다고 명시되어 있다. CSRF 공격 방식은 인증된 사용자의 세션을 서버에 저장하고, 클라이언트는 세션 정보를 쿠키에 저장하는 것을 전제로 한다. 따라서 REST API 서버와 같이 서버에 인증 정보를 저장하지 않는 무상태(Stateless) 서비스인 경우에는 CSRF 보안 비활성화를 고려해보는 게 좋다.

스프링 진영에서 밀고 있는 Thymeleaf 템플릿 엔진의 경우에는 별다른 설정 없이, 아래의 코드만 페이지에 추가하면 알아서 동작한다.

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

하지만 Mustache(이하 머스테치) 에서는 이런 기능을 기본적으로 제공해주지 않는다. 정석대로라면, 인터셉트로 토큰 값을 받아 컨트롤러에서 모델 어트리뷰트에 넣어 전달해 주는 것이 맞겠지만 그러기엔 너무 번거롭다. 아니나 다를까, 구글에서 이 주제와 관련하여 검색을 해보니 아주 간단하게 해결하는 방법이 있었다. (오오, 구글 신은 모든 것을 알고 계신다...)

우선 application.properties에 다음의 내용을 추가해준다.

spring.mustache.servlet.expose-request-attributes=true

application.yml을 쓰는 경우에는 다음과 같이 추가한다.

spring:
  mustache:
    servlet:
      expose-request-attributes: true

그 다음, CSRF 토큰 인증이 필요한 페이지에 다음 내용을 추가한다.

<input type="hidden" name="_csrf" value="{{ _csrf.token }}" />

이제, 머스테치를 사용하더라도 CSRF 보안을 제대로 사용할 수 있을 것이다!


참고한 문헌 및 글

  1. Mustache CSRF 적용 및 문제해결 (tistory.com)
  2. java - How to use Spring Security with Mustache? - Stack Overflow