Skip to content

Step-up re-authentication does not rotate the session id (CSRF token does rotate) #369

Description

@devondragon

Summary

When step-up (SUF-02) re-runs the passkey login ceremony while the user is already authenticated, the servlet session id (JSESSIONID) is not rotated. The CSRF token is rotated. This was verified in a browser as part of SpringUserFrameworkDemoApp#75, whose acceptance criteria expected the session id to change on re-assertion.

Evidence (browser, library 5.3.3, step-up enabled)

Captured immediately before submitting a gated operation and immediately after the step-up ceremony (/login/webauthn re-run mid-session):

JSESSIONID before = 562CB176BDC07A3C3910BEAE8BE5BE9C
JSESSIONID after  = 562CB176BDC07A3C3910BEAE8BE5BE9C   (unchanged)

_csrf before = 5918qjK-pVpDMMp00naRBGQJb-5In7sVocHP3LlHgGRPzEV...
_csrf after  = hYOlzFKos_wbhhMEBPW3qm8UwP5PLxcDAPiIgaixc3cY8_9...  (rotated)

Why this happens

Step-up depends on factor merging (setMfaEnabled(true) on the authentication processing filters, MfaFilterMergingConfiguration). In MFA/merge mode the filter merges the new factor onto the already-authenticated principal rather than running a fresh authentication, so the session-fixation strategy (ChangeSessionIdAuthenticationStrategy) does not rotate the id. CsrfAuthenticationStrategy still runs, so the CSRF token rotates.

Is it a problem?

Arguably not a vulnerability: the principal is unchanged and the session was already authenticated, so preserving the id introduces no fixation vector (there is no pre-auth id being "upgraded"). But it contradicts the reasonable expectation — stated in the demo issue's acceptance criteria — that a full re-login rotates the session id, and it is worth documenting the intended behavior either way.

Ask

  • Confirm whether preserving the session id across a step-up re-assertion is intended, and document it (CONFIG.md / MIGRATION.md) alongside the note that CSRF rotates.
  • If id rotation is desired for step-up, decide how that interacts with factor merging (which deliberately does not rotate on each factor).

Client consequence already handled in the demo: because CSRF rotates, a client that stays on the page after step-up must refresh its CSRF token before retrying (SpringUserFrameworkDemoApp#75 adds a GET /csrf for exactly this).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions