Skip to content

Commit

Permalink
improve CSRF Token Handling for SPA (#27908)
Browse files Browse the repository at this point in the history
  • Loading branch information
yhao3 authored Nov 23, 2024
1 parent 62462b9 commit 14007d2
Showing 1 changed file with 10 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,6 @@ import org.springframework.security.web.SecurityFilterChain;
<%_ if (!skipClient || authenticationUsesCsrf) { _%>
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
<%_ } _%>
<%_ if (authenticationUsesCsrf) { _%>
import tech.jhipster.web.filter.CookieCsrfFilter;
<%_ } _%>
<%_ if (!skipClient) { _%>
import <%= packageName %>.web.filter.SpaWebFilter;
<%_ } _%>
Expand Down Expand Up @@ -175,11 +172,6 @@ public class SecurityConfiguration {
<%_ if (!skipClient) { _%>
.addFilterAfter(new SpaWebFilter(), BasicAuthenticationFilter.class)
<%_ } _%>
<%_ if (!applicationTypeMicroservice) { _%>
<%_ if (authenticationUsesCsrf) { _%>
.addFilterAfter(new CookieCsrfFilter(), BasicAuthenticationFilter.class)
<%_ } _%>
<%_ } _%>
<%_ if (!skipClient) { _%>
.headers(headers -> headers
.contentSecurityPolicy(csp -> csp.policyDirectives(jHipsterProperties.getSecurity().getContentSecurityPolicy()))
Expand Down Expand Up @@ -376,23 +368,26 @@ public class SecurityConfiguration {
<%_ if (authenticationUsesCsrf && !applicationTypeMicroservice) { _%>

/**
* Custom CSRF handler to provide BREACH protection.
* Custom CSRF handler to provide BREACH protection for Single-Page Applications (SPA).
*
* @see <a href="https://docs.spring.io/spring-security/reference/servlet/exploits/csrf.html#csrf-integration-javascript-spa">Spring Security Documentation - Integrating with CSRF Protection</a>
* @see <a href="https://github.com/jhipster/generator-jhipster/pull/25907">JHipster - use customized SpaCsrfTokenRequestHandler to handle CSRF token</a>
* @see <a href="https://stackoverflow.com/q/74447118/65681">CSRF protection not working with Spring Security 6</a>
*/
static final class SpaCsrfTokenRequestHandler extends CsrfTokenRequestAttributeHandler {

private final CsrfTokenRequestHandler delegate = new XorCsrfTokenRequestAttributeHandler();
static final class SpaCsrfTokenRequestHandler implements CsrfTokenRequestHandler {
private final CsrfTokenRequestHandler plain = new CsrfTokenRequestAttributeHandler();
private final CsrfTokenRequestHandler xor = new XorCsrfTokenRequestAttributeHandler();

@Override
public void handle(HttpServletRequest request, HttpServletResponse response, Supplier<CsrfToken> csrfToken) {
/*
* Always use XorCsrfTokenRequestAttributeHandler to provide BREACH protection of
* the CsrfToken when it is rendered in the response body.
*/
this.delegate.handle(request, response, csrfToken);
this.xor.handle(request, response, csrfToken);

// Render the token value to a cookie by causing the deferred token to be loaded.
csrfToken.get();
}

@Override
Expand All @@ -404,15 +399,15 @@ public class SecurityConfiguration {
* raw CsrfToken.
*/
if (StringUtils.hasText(request.getHeader(csrfToken.getHeaderName()))) {
return super.resolveCsrfTokenValue(request, csrfToken);
return this.plain.resolveCsrfTokenValue(request, csrfToken);
}
/*
* In all other cases (e.g. if the request contains a request parameter), use
* XorCsrfTokenRequestAttributeHandler to resolve the CsrfToken. This applies
* when a server-side rendered form includes the _csrf request parameter as a
* hidden input.
*/
return this.delegate.resolveCsrfTokenValue(request, csrfToken);
return this.xor.resolveCsrfTokenValue(request, csrfToken);
}
}
<%_ } _%>
Expand Down

0 comments on commit 14007d2

Please sign in to comment.