skip to content

What is session fixation and how does Spring Security protect against it by default?

level: juniorimportance: must knowfreq 60%

answer

  1. attacker plants ID, victim logs in, same ID reused
  2. rotate session ID at login
  3. default = changeSessionId()
  4. migrateSession / newSession / none
  5. moot under STATELESS

basics

~20 s

Session fixation is when an attacker forces a victim to use a known session ID, then hijacks it after login. Spring Security defends by changing the session ID at login (changeSessionId), so the old ID is useless.

solid answer

~40 s

Session fixation is an attack where the attacker plants a session ID the victim then authenticates against; because the ID never changed at login, the attacker reuses that same ID to ride the now-authenticated session. Spring Security prevents this by rotating the session identifier the moment a user authenticates. In Spring Security 6 the default strategy is changeSessionId(): it keeps the existing HttpSession and its attributes but asks the Servlet container (via HttpServletRequest.changeSessionId(), Servlet 3.1+) to issue a brand-new session ID. Any ID the attacker previously fixed is now invalid. This is configured under http.sessionManagement().sessionFixation(). Alternatives are migrateSession(), newSession(), and none() (disabled). Protection only matters when sessions exist; with SessionCreationPolicy.STATELESS there is no session to fix.

code

java · 11 lines
java
@Bean
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    http
        .authorizeHttpRequests(auth -> auth.anyRequest().authenticated())
        .formLogin(Customizer.withDefaults())
        .sessionManagement(session -> session
            // default in Spring Security 6; shown explicitly for clarity
            .sessionFixation(fixation -> fixation.changeSessionId())
        );
    return http.build();
}

go deeper

for a junior

Know the definition and that Spring changes the session ID at login by default.

for a middle

Name all four strategies and how changeSessionId differs from migrate/new.

for a senior

Tie it to the authentication strategy that fires on login and to Servlet 3.1 changeSessionId(); note interplay with concurrent-session control.

for a principal

Reason about SessionIdChangedEvent, Spring Session / distributed stores, and when disabling is defensible behind an external rotation guarantee.

**The attack.** An HTTP session is tracked by a session identifier, usually in the `JSESSIONID` cookie. In a *session fixation* attack the attacker first obtains or plants a specific session ID (e.g. tricks the victim into visiting `https://app/?JSESSIONID=abc` or sets the cookie via a subdomain/XSS). The victim then logs in. If the application keeps the *same* session ID across the login boundary, the session is now authenticated as the victim but its ID is a value the attacker already knows — so the attacker replays that ID and is logged in as the victim. **The fix: rotate the ID at authentication.** The universal defense is to change the session identifier the instant privilege level changes (login). Spring Security does this automatically through `SessionManagementFilter`/`SessionFixationProtectionStrategy` (or the newer `ChangeSessionIdAuthenticationStrategy`) which run when an `Authentication` succeeds. **Spring Security strategies** (configured via the `sessionManagement { sessionFixation { ... } }` DSL): - **`changeSessionId()` — the default in Spring Security 4+ (Servlet 3.1+).** Keeps the same `HttpSession` object and all its attributes, but calls `HttpServletRequest.changeSessionId()` so the container assigns a new ID. Lightweight, preserves attributes, no session recreation. - **`migrateSession()`** — creates a *new* `HttpSession` and copies the old session's attributes into it. Used on older containers without `changeSessionId` support. - **`newSession()`** — creates a new session but does **not** copy attributes (except a few Spring Security internals). Anything you stored pre-login is lost. - **`none()`** — disables fixation protection entirely; the ID is not rotated. Almost never correct. **Key terms.** - *HttpSession*: server-side store of per-user state, keyed by the session ID cookie. - *SessionManagementFilter / authentication strategy*: the Spring Security component that fires on successful login and applies the fixation strategy. **Edge cases / gotchas.** - Fixation protection is only relevant when a session actually exists. Under `SessionCreationPolicy.STATELESS` Spring Security never creates a session, so there is nothing to rotate and the setting is moot. - Changing the ID triggers `HttpSessionIdChangedEvent`; components tracking sessions by ID (e.g. Spring Session, `SessionRegistry`) must handle the change. Spring Security's concurrent-session control wires this for you. - If you disable it with `none()` you reopen the vulnerability — only do so with an external mechanism guaranteeing ID rotation. **When to use which.** Accept the default `changeSessionId()` on any modern container. Use `migrateSession()` only for pre-Servlet-3.1 environments. `newSession()` when you explicitly want a clean slate at login and are sure no needed attributes were set beforehand.

  • What is the difference between migrateSession() and newSession()?
    Both create a brand-new HttpSession. migrateSession() copies the old session's attributes into the new one; newSession() starts empty (only a few Spring Security internal attributes are carried over), so any pre-login data is discarded.
  • Why does changeSessionId() not need to create a new HttpSession?
    Servlet 3.1 added HttpServletRequest.changeSessionId(), which asks the container to assign a new ID to the existing session object while keeping all attributes. No copy/recreate needed, so it is cheaper and preserves state.

saying these in an interview costs you the question

  • Claiming Spring Security's default is migrateSession() (it is changeSessionId() since 4.x on Servlet 3.1+).
  • Saying fixation protection means logging the user out on login.
  • Believing session fixation still applies under SessionCreationPolicy.STATELESS.

context