skip to content

What is CSRF, and how does Spring Security protect against it by default?

level: juniorimportance: must knowfreq 72%

answer

  1. browser auto-sends cookies cross-site
  2. CsrfFilter + secret token on POST/PUT/DELETE/PATCH
  3. GET/HEAD/OPTIONS/TRACE exempt
  4. HttpSessionCsrfTokenRepository default
  5. mismatch -> 403

basics

~10 s

CSRF tricks a logged-in user's browser into sending an unwanted state-changing request using their cookies. Spring Security defends with a secret token (CsrfFilter) that must accompany every POST/PUT/DELETE/PATCH, which an attacker's site cannot know.

solid answer

~40 s

Cross-Site Request Forgery (CSRF) abuses the fact that browsers automatically attach ambient credentials (session cookies) to any request to your domain, so a malicious page can silently trigger a state-changing action as the victim. Spring Security's `CsrfFilter` requires a per-session/per-request secret token on unsafe methods (POST, PUT, DELETE, PATCH); safe methods (GET, HEAD, OPTIONS, TRACE) are exempt. The token comes back on the `X-CSRF-TOKEN` header or `_csrf` form parameter and is compared against the `CsrfTokenRepository` (by default `HttpSessionCsrfTokenRepository`, stored server-side in the session). Because the attacker's origin cannot read your token, forged requests are rejected with 403. CSRF protection is enabled automatically in Spring Security; you configure it via `http.csrf(...)` in the `SecurityFilterChain`.

code

java · 14 lines
java
@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            .authorizeHttpRequests(auth -> auth.anyRequest().authenticated())
            .formLogin(Customizer.withDefaults())
            // CSRF is ON by default; this shows explicit, default synchronizer-token config
            .csrf(Customizer.withDefaults());
        return http.build();
    }
}

go deeper

for a junior

Know the one-sentence definition, that browsers auto-send cookies, and that Spring uses a token on state-changing requests.

for a middle

Explain the synchronizer-token pattern, which methods are protected, and the CsrfFilter/CsrfTokenRepository roles.

for a senior

Discuss default HttpSession storage vs cookie repo tradeoffs and how tokens reach a JS client.

for a principal

Frame CSRF as an ambient-credential problem and connect the defense choice to the app's auth model and deployment topology.

## What CSRF is **Cross-Site Request Forgery (CSRF)** is an attack where a malicious web page causes the victim's browser to send a state-changing request to a site the victim is already authenticated to. It works because browsers **automatically attach ambient credentials** — cookies, HTTP Basic auth, TLS client certs — to every request to a domain, regardless of which page initiated it. If `evil.com` embeds `<form action="https://bank.com/transfer" method="post">` and auto-submits it, the victim's `bank.com` session cookie rides along and the transfer executes as the victim. Key enabling condition: **authentication via something the browser sends automatically** (a cookie). If auth requires an explicit header the attacker's page cannot set cross-origin, CSRF does not apply (see the bearer-token question). ## How Spring Security defends: the synchronizer token pattern Spring Security inserts a **`CsrfFilter`** into the filter chain. The idea: the server issues a **secret, unpredictable token** that the legitimate frontend receives and echoes back on every unsafe request. The attacker's page cannot read this token (same-origin policy blocks reading your responses), so it cannot forge a valid request. - **`CsrfToken`** — an object holding the token value, the header name (`X-CSRF-TOKEN`), and the parameter name (`_csrf`). - **`CsrfTokenRepository`** — where the token is stored/loaded. Default is **`HttpSessionCsrfTokenRepository`** (server-side in the `HttpSession`). Alternative: **`CookieCsrfTokenRepository`** (double-submit cookie, stateless). - **`CsrfFilter`** — on each request, if the method **requires** a token, it loads the expected token from the repository and compares it to the value supplied on the request (header or `_csrf` parameter). On mismatch it throws `InvalidCsrfTokenException`; if none supplied, `MissingCsrfTokenException`. Both surface as **HTTP 403** via the `AccessDeniedHandler`. ## Which methods are protected By `DefaultRequiresCsrfMatcher`, tokens are required only for **unsafe methods**: `POST`, `PUT`, `DELETE`, `PATCH`. **Safe/idempotent methods** — `GET`, `HEAD`, `OPTIONS`, `TRACE` — are exempt because they should not change state. (This is also why using GET for mutations is a security bug: it bypasses CSRF protection.) ## Enabled by default With the Spring Security starter, CSRF protection is **on by default**. For classic server-rendered apps (Thymeleaf forms), the token is auto-injected into forms, so it "just works". You only touch it when building SPAs/JS clients (you must read and resend the token) or when you legitimately disable it (stateless bearer APIs). ## Configuration entry point ```java http.csrf(csrf -> csrf .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())); ``` ## Gotchas - Disabling CSRF wholesale "to make POSTs work" while still using cookie auth **reopens the hole** — the classic beginner mistake. - GET endpoints that mutate state escape CSRF checks entirely. - SPAs must explicitly read the token (from cookie or a bootstrap endpoint) and set the `X-CSRF-TOKEN` header.

  • Why are GET requests exempt from CSRF checks?
    GET is defined as safe/idempotent and must not change state, so there is nothing to forge. The corollary: never perform mutations on GET, because doing so silently bypasses CSRF protection.
  • Where is the token stored by default, and what does that imply?
    In the HttpSession via HttpSessionCsrfTokenRepository, so the default synchronizer-token approach requires server-side session state; that matters for horizontally scaled/stateless deployments.

saying these in an interview costs you the question

  • Claiming CSRF lets an attacker read the victim's data (it only causes writes; same-origin policy still blocks reading responses)
  • Saying HTTPS or CORS alone prevents CSRF
  • Believing GET requests are also protected by the token
  • Thinking disabling CSRF is always safe

context