CSRF (Cross-Site Request Forgery) attacks force authenticated users to submit unintended requests to web applications where they maintain active sessions. Unlike XSS attacks that steal credentials, CSRF exploits the trust relationship between the browser and the server. When a user authenticates, the server establishes a session stored in browser cookies. Subsequent requests automatically include these cookies, allowing attackers to forge requests if they trick the user into visiting a malicious page that submits forms to the target domain.
Spring Security automatically enables CSRF protection starting from version 4. The framework intercepts state-changing requests (POST, PUT, DELETE, PATCH) and validates a synchronizer token. This token must accompany each request, typically embedded in forms or headers, preventing unauthorized cross-origin submissions.
To implement form-based authentication with CSRF protection enabled, first create a controller endpoint that serves the authentication view:
@Controller
public class AuthenticationController {
@GetMapping("/signin")
public String authenticationPage() {
return "security/signin";
}
}
Next, construct the Thymeleaf template with the CSRF token included as a hidden field. The template engine automatically injects the token value generated by Spring Security's CsrfToken repository:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Authentication</title>
</head>
<body>
<form th:action="@{/signin}" method="post">
<input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}" />
<label for="userId">Account:</label>
<input type="text" id="userId" name="userId" required /><br/>
<label for="secret">Password:</label>
<input type="password" id="secret" name="secret" required /><br/>
<button type="submit">Authenticate</button>
</form>
</body>
</html>
In the security configuration class, avoid invoking csrf().disable() unless integrating with stateless APIs where session management differs. For traditional server-rendered applications, retain the default protection:
@Configuration
@EnableWebSecurity
public class ApplicationSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/signin").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/signin")
.defaultSuccessUrl("/dashboard")
.and()
.csrf();
}
}
When processing logout or AJAX requests, include the token in the request header using X-CSRF-TOKEN or configure a custom CsrfTokenRepository to persist tokens across sessions if needed.