×
☰ See All Chapters

Enhanced Security Monitoring with CSRF Token Logging Filter in Spring Security

In Spring Security, CSRF (Cross-Site Request Forgery) protection is enabled by default to prevent unauthorized mutating operations (POST, PUT, DELETE). However, certain HTTP methods like GET, HEAD, TRACE, and OPTIONS are exempt from CSRF protection.

How CSRF Protection Works

  1. Token Generation: When a user accesses HTTP GET endpoint, CsrfFilter generates a unique CSRF token. The CsrfFilter utilizes a component called CsrfTokenRepository to handle CSRF token management tasks, such as generating new tokens, storing tokens, and eventually invalidating them. By default, the CsrfTokenRepository stores the token on the HTTP session and generates tokens as random universally unique identifiers (UUIDs). 

However, if the default behavior of the CsrfTokenRepository does not meet your specific requirements, you have the flexibility to implement your own custom CsrfTokenRepository. This allows you to tailor the CSRF token management process to suit the needs of your application. Whether you need a different storage mechanism, token generation strategy, or token invalidation approach, implementing a custom CsrfTokenRepository enables you to achieve the desired functionality.

  1. Token Validation: For mutating operations (POST, PUT, DELETE), the CsrfFilter expects requests to include this token in X-CSRF-TOKEN header. It ensures that requests originate from the application itself. Spring Security's CsrfFilter is a key component in the filter chain. It allows exempt HTTP methods and validates tokens for mutating requests. Invalid tokens lead to a rejection with HTTP 403 Forbidden status. 

In previous chapters, we disabled CSRF protection using http.csrf().disable() to allow HTTP POST methods. However, disabling CSRF protection is not recommended in real-time applications. Instead, to invoke endpoints like POST, PUT, and DELETE, we need to include the CSRF token in the X-CSRF-TOKEN header.

It's important to note that providing the correct CSRF token alone is not sufficient for a successful call. Additionally, you must include the session ID (JSESSIONID) in the Cookie header. This is because the default implementation of CsrfTokenRepository stores the CSRF token value in the session.

Let's create an example application by implementing a CsrfLoggingFilter. This filter will extract the generated CSRF token from the _csrf attribute of the HTTP request and log it. After the CsrfFilter is applied, we can access the _csrf attribute to retrieve the token value. For this demonstration, we'll add a custom filter after the CsrfFilter, following the principles learned in previous chapters. This custom filter will print the CSRF token to the console when we call the endpoint using HTTP GET. We can then copy the token value from the console and use it for making mutating calls with HTTP POST.

import lombok.extern.slf4j.Slf4j;
import org.springframework.security.web.csrf.CsrfToken;

import javax.servlet.*;
import java.io.IOException;

@Slf4j
public class CSRFTokenLoggingFilter implements Filter {
   
@Override
   
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
           
throws IOException, ServletException {
       
Object o = request.getAttribute("_csrf");
       
CsrfToken token = (CsrfToken) o;
       
log.info("CSRF token: " + token.getToken());
       filterChain.doFilter(request, response);
   }
}

 

import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.web.csrf.CsrfFilter;

@Configuration
public class ApplicationWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {

   
@Override
   
protected void configure(HttpSecurity http) throws Exception {
       http.addFilterAfter(
new CSRFTokenLoggingFilter(), CsrfFilter.class)
               .authorizeRequests()
               .anyRequest().permitAll();
   }

}

 

csrf-token-logging-filter-in-spring-security-0
 
csrf-token-logging-filter-in-spring-security-1
 

First, execute the following command in your terminal:

curl -v https://localhost:8080/hello

After executing the above GET curl command, retrieve the value of the X-CSRF-TOKEN from the console output.

Next, extract the Cookie value from the response in your command prompt after executing the aforementioned GET curl command.

Once you have obtained the X-CSRF-TOKEN value and the Cookie value, proceed to execute the following curl command:

curl --request POST https://localhost:8080/hello --header "X-CSRF-TOKEN: 3e14c6c3-8828-41d9-85fe-cba2d0d3649c" --header "Cookie: JSESSIONID=CDCEF35B477664D334F604C13361065A"

 


All Chapters
Author