spring-projects / spring-projects/spring-security

Customizing AccessDeniedHandler for MissingCsrfTokenException when an InvalidSessionStrategy exists

Open
#13,321 7 comments 0 reactions 1 assignee View on GitHub

Nobody has claimed this yet.

status: feedback-provided
Dominant language
Java
Stars
9.6k
Forks
6.3k
Avg merge
2d 11h
Merged PRs (30d)
52

Description

Use case

Signaling a CSRF problem to client app via 403 or some other status-code, while invalid sessions result in 401. For example in a SPA 401 might trigger re-authentication, while missing CSRF token might be an issue for a single request (which wouldn't need / want re-authentication).

Problem

I didn't find a "proper" way to handle / customize handling for missing CSRF token (MissingCsrfTokenException). I was expecting to get the error into AccessDeniedHandler specified in the ExceptionHandlingConfigurer.

I tracked the possible cause to CsrfConfigurer.createAccessDeniedHandler (code below) where a defined InvalidSessionStrategy results in instantiating a DelegatingAccessDeniedHandler with MissingCsrfTokenException mapped to an instantiated InvalidSessionAccessDeniedHandler, which in turn calls invalidSessionStrategy.onInvalidSessionDetected and drops the info on cause / exception. So a defined InvalidSessionStrategy takes precedence over an AccessDeniedHandler.

It surprised me a bit that a missing CSRF token leads to "invalid session detected".

    private AccessDeniedHandler createAccessDeniedHandler(H http) {
        InvalidSessionStrategy invalidSessionStrategy = getInvalidSessionStrategy(http);
        AccessDeniedHandler defaultAccessDeniedHandler = getDefaultAccessDeniedHandler(http);
        if (invalidSessionStrategy == null) {
            return defaultAccessDeniedHandler;
        }
        InvalidSessionAccessDeniedHandler invalidSessionDeniedHandler = new InvalidSessionAccessDeniedHandler(
                invalidSessionStrategy);
        LinkedHashMap<Class<? extends AccessDeniedException>, AccessDeniedHandler> handlers = new LinkedHashMap<>();
        handlers.put(MissingCsrfTokenException.class, invalidSessionDeniedHandler);
        return new DelegatingAccessDeniedHandler(handlers, defaultAccessDeniedHandler);
    }

https://github.com/spring-projects/spring-security/blob/371541a5cfee80e149d3a5308c63f0f81aeb6e2a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/CsrfConfigurer.java#LL311C2-L322C3

Possible solution

It would be nice to just handle the MissingCsrfTokenException directly via AccessDeniedHandler defined in ExceptionHandlingConfigurer (just like InvalidCsrfTokenException can be handled) or specify a custom AccessDeniedHandler for the CsrfConfigurer, which would take precedence over InvalidSessionStrategy.

Workarounds

Easy workaround is to have a custom CsrfTokenRequestAttributeHandler with resolveCsrfTokenValue returning String "null" instead of null-value CSRF token is missing, leading to InvalidCsrfTokenException instead of MissingCsrfTokenExeption.

It's also possible to handle the issue in the InvalidSessionStrategy.onInvalidSessionDetected by checking if the request should've had CSFR-token and whether it did, but this would start duplicating CSRF-logic there.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.