🛡️ CSRF Security Tutorial

Understanding Cross-Site Request Forgery and Spring Security Protection

What is CSRF (Cross-Site Request Forgery)?

CSRF is a type of malicious exploit where unauthorized commands are transmitted from a user that the web application trusts. It tricks a user's browser into executing unwanted actions on a web application in which they're currently authenticated.

Key Point: CSRF attacks exploit the trust that a web application has in a user's browser, not the trust the user has in the web application.

How CSRF Attacks Work:

  1. User logs into a legitimate website (like their bank)
  2. Website creates a session and stores authentication cookies
  3. User visits a malicious website while still logged in
  4. Malicious site sends requests to the legitimate site using the user's credentials
  5. Legitimate site processes these requests as if they came from the user

CSRF Attack Simulation

🚨 Malicious Website Example

Imagine you're logged into your bank account. A malicious website could contain this hidden form:

<!-- This form is hidden on a malicious website -->
<form id="maliciousTransfer" action="https://yourbank.com/transfer" method="POST" style="display:none;">
    <input type="hidden" name="to" value="attacker@evil.com" />
    <input type="hidden" name="amount" value="1000" />
</form>

<script>
    // Auto-submit when page loads
    document.getElementById('maliciousTransfer').submit();
</script>

Problem: Your browser automatically includes your authentication cookies with this request, making the bank think YOU initiated the transfer!

Why CSRF Tokens Are Needed

CSRF tokens solve the fundamental problem: How can a server distinguish between legitimate requests from the user and forged requests from malicious sites?

CSRF Token Properties:

  • Unpredictable: Cryptographically random values that attackers cannot guess
  • Unique: Different for each session or request
  • Secret: Only known to the legitimate website and user
  • Validated: Server checks the token on every state-changing request

Generate a Sample CSRF Token:

Spring Security CSRF Protection

Spring Security provides built-in CSRF protection that's enabled by default. Here's how it works:

1. Enable CSRF Protection (Default)

@Configuration @EnableWebSecurity public class SecurityConfig { @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http .csrf(csrf -> csrf .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()) .ignoringRequestMatchers("/api/public/**") // Exclude specific endpoints ) .authorizeHttpRequests(authz -> authz .requestMatchers("/login", "/register").permitAll() .anyRequest().authenticated() ); return http.build(); } }

2. HTML Form Integration

<!-- Spring automatically includes CSRF token in forms -->
<form th:action="@{/transfer}" method="post">
    <!-- This hidden input is automatically added by Thymeleaf -->
    <input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}"/>
    
    <input type="text" name="recipient" placeholder="Recipient"/>
    <input type="number" name="amount" placeholder="Amount"/>
    <button type="submit">Transfer Money</button>
</form>

3. AJAX Integration

// Include CSRF token in AJAX requests var token = $("meta[name='_csrf']").attr("content"); var header = $("meta[name='_csrf_header']").attr("content"); $.ajaxSetup({ beforeSend: function(xhr) { xhr.setRequestHeader(header, token); } }); // Or include in request body $.post("/transfer", { recipient: "john@example.com", amount: 100, _token: token });

Interactive Demo: Protected Form

✅ CSRF Protected Form

This form demonstrates how Spring Security protects against CSRF attacks:

Try Without CSRF Token:

Best Practices & Advanced Configuration

1. Custom CSRF Token Repository

@Bean
public CsrfTokenRepository csrfTokenRepository() {
    HttpSessionCsrfTokenRepository repository = new HttpSessionCsrfTokenRepository();
    repository.setHeaderName("X-XSRF-TOKEN");
    repository.setParameterName("_csrf");
    return repository;
}

2. Conditional CSRF Protection

http.csrf(csrf -> csrf
    .requireCsrfProtectionMatcher(request -> 
        // Only protect state-changing operations
        !request.getMethod().equals("GET") && 
        !request.getMethod().equals("HEAD") &&
        !request.getMethod().equals("OPTIONS")
    )
);

3. Custom CSRF Failure Handler

@Component
public class CustomCsrfFailureHandler implements AccessDeniedHandler {
    
    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response, 
                      AccessDeniedException exception) throws IOException {
        
        if (exception instanceof CsrfException) {
            response.setStatus(HttpStatus.FORBIDDEN.value());
            response.getWriter().write("CSRF token validation failed");
        }
    }
}

🔒 Security Checklist:

  • ✅ Enable CSRF protection for all state-changing operations
  • ✅ Use HTTPS to prevent token interception
  • ✅ Implement proper token validation on the server
  • ✅ Use secure, random token generation
  • ✅ Set appropriate token expiration times
  • ✅ Handle CSRF failures gracefully

⚠️ Simulated CSRF Attack (HTML Form with Method Override)

This form simulates a CSRF attack that submits a POST request with a hidden `_method=DELETE` to delete a student record.

🛠️ Step Before Simulating CSRF

Before clicking 'Simulate CSRF Attack', configure your Spring Boot SecurityConfig like this:

// Step 1: Import Customizer.withDefaults
import static org.springframework.security.config.Customizer.withDefaults;

// Step 2: Define SecurityFilterChain bean
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    http
        .csrf(csrf -> csrf
            .ignoringRequestMatchers("/students/**") // Disable CSRF for student endpoints
        )
        .authorizeHttpRequests(auth -> auth
            .anyRequest().authenticated()
        )
        .formLogin(withDefaults())     // Enable default form login
        .httpBasic(withDefaults());    // Enable HTTP Basic authentication

    return http.build();
}

// Step 3: Enable HiddenHttpMethodFilter if using _method override for DELETE
@Bean
public HiddenHttpMethodFilter hiddenHttpMethodFilter() {
    return new HiddenHttpMethodFilter();
}
Important: This form relies on your server-side framework interpreting `_method=DELETE` in POST requests. In Spring, you must enable the HiddenHttpMethodFilter.