DEV Community

Salad Lam
Salad Lam

Posted on

Spring Security: CSRF protection

Code is extracted from my notice board example application, which uses Spring Security 5.6.7

CsrfFilter filter

CSRF protection is on by default when configuring HttpSecurity. A CsrfFilter is created and has the following function.

When the request method is not "GET", "HEAD", "TRACE" or "OPTIONS". To check if the provided CSRF matches record in the token registry. If not matched, a 403 forbidden response will be returned.

Otherwise, a SaveOnAccessCsrfToken is generated and saved as a HttpServletRequest attribute with name org.springframework.security.web.csrf.CsrfToken and _csrf. This token will not persist unless it is accessed by a template engine. When persistence it is done by HttpSessionCsrfTokenRepository instance and the token will be saved as a HttpSession attribute with name org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository.CSRF_TOKEN.

Token access by thymeleaf engine

When rendering http form tag, such as

<form method="post" th:action="@{/loginHandler}" class="ui large form">
Enter fullscreen mode Exit fullscreen mode

a hidden input tag will append afterward to provide CSRF token. In other word

<form method="post" action="/loginHandler" class="ui large form"><input type="hidden" name="_csrf" value="3c2ffa6d-ab75-41f3-ba10-7c423bf56071"/>
Enter fullscreen mode Exit fullscreen mode

This is done by SpringActionTagProcessor. Then following method will be called to access CSRF token.

org.thymeleaf.spring5.requestdata.RequestDataValueProcessorUtils#getExtraHiddenFields
org.thymeleaf.spring5.context.webmvc.SpringWebMvcThymeleafRequestDataValueProcessor#getExtraHiddenFields
org.springframework.security.web.servlet.support.csrf.CsrfRequestDataValueProcessor#getExtraHiddenFields
Enter fullscreen mode Exit fullscreen mode
@Override
public Map<String, String> getExtraHiddenFields(HttpServletRequest request) {
    if (Boolean.TRUE.equals(request.getAttribute(this.DISABLE_CSRF_TOKEN_ATTR))) {
        request.removeAttribute(this.DISABLE_CSRF_TOKEN_ATTR);
        return Collections.emptyMap();
    }
    CsrfToken token = (CsrfToken) request.getAttribute(CsrfToken.class.getName());
    if (token == null) {
        return Collections.emptyMap();
    }
    Map<String, String> hiddenFields = new HashMap<>(1);
    hiddenFields.put(token.getParameterName(), token.getToken());
    return hiddenFields;
}
Enter fullscreen mode Exit fullscreen mode

Reference

  1. Cross Site Request Forgery (CSRF)

Top comments (0)