Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

use customized SpaCsrfTokenRequestHandler to handle CSRF token #25907

Merged
merged 2 commits into from
Apr 23, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,10 @@ import tech.jhipster.web.filter.CookieCsrfFilter;
<%_ if (!skipClient) { _%>
import <%= packageName %>.web.filter.SpaWebFilter;
<%_ } _%>
<%_ if (authenticationUsesCsrf && !applicationTypeMicroservice) { _%>
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
<%_ } _%>
<%_ if (authenticationTypeJwt || (authenticationTypeOauth2 && applicationTypeMicroservice)) { _%>
import org.springframework.security.config.http.SessionCreationPolicy;
<%_ } _%>
Expand Down Expand Up @@ -84,6 +88,9 @@ import org.springframework.security.oauth2.core.oidc.user.OidcUserAuthority;
<%_ } _%>
import java.util.*;
<%_ } _%>
<%_ if (authenticationUsesCsrf && !applicationTypeMicroservice) { _%>
import java.util.function.Supplier;
<%_ } _%>
<%_ if (authenticationTypeSession) { _%>
import org.springframework.http.HttpStatus;
import org.springframework.security.web.authentication.HttpStatusEntryPoint;
Expand All @@ -94,8 +101,7 @@ import org.springframework.security.web.authentication.RememberMeServices;
<%_ } _%>
<%_ } _%>
<%_ if (authenticationUsesCsrf && !applicationTypeMicroservice) { _%>
import org.springframework.security.web.csrf.CookieCsrfTokenRepository;
import org.springframework.security.web.csrf.CsrfTokenRequestAttributeHandler;
import org.springframework.security.web.csrf.*;
<%_ } _%>
<%_ if (authenticationTypeOauth2) { _%>
import <%= packageName %>.security.oauth2.JwtGrantedAuthorityConverter;
Expand All @@ -112,6 +118,9 @@ import <%= packageName %>.security.oauth2.CustomClaimConverter;
<%_ if(!skipClient) { _%>
import org.springframework.security.web.header.writers.ReferrerPolicyHeaderWriter;
<%_ } _%>
<%_ if (authenticationUsesCsrf && !applicationTypeMicroservice) { _%>
import org.springframework.util.StringUtils;
<%_ } _%>
import org.springframework.security.web.servlet.util.matcher.MvcRequestMatcher;
import org.springframework.web.servlet.handler.HandlerMappingIntrospector;

Expand All @@ -126,7 +135,7 @@ public class SecurityConfiguration {

private final Environment env;
<%_ } _%>

private final JHipsterProperties jHipsterProperties;
<%_ if (authenticationTypeSession && generateUserManagement) { _%>

Expand All @@ -141,7 +150,7 @@ public class SecurityConfiguration {
public SecurityConfiguration(<% if (devDatabaseTypeH2Any) { %>Environment env, <% } %><% if (authenticationTypeSession && generateUserManagement) { %>RememberMeServices rememberMeServices, <% } %> JHipsterProperties jHipsterProperties) {
<%_ if (devDatabaseTypeH2Any) { _%>
this.env = env;
<%_ } _%>
<%_ } _%>
<%_ if (authenticationTypeSession && generateUserManagement) { _%>
this.rememberMeServices = rememberMeServices;
<%_ } _%>
Expand All @@ -164,8 +173,7 @@ public class SecurityConfiguration {
.csrf(csrf -> csrf
<%_ if (authenticationUsesCsrf && !applicationTypeMicroservice) { _%>
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
// See https://stackoverflow.com/q/74447118/65681
.csrfTokenRequestHandler(new CsrfTokenRequestAttributeHandler()))
.csrfTokenRequestHandler(new SpaCsrfTokenRequestHandler()))
<%_ } else { _%>
.disable())
<%_ } _%>
Expand Down Expand Up @@ -364,4 +372,46 @@ public class SecurityConfiguration {
return jwtDecoder;
}
<%_ } _%>
<%_ if (authenticationUsesCsrf && !applicationTypeMicroservice) { _%>

/**
* Custom CSRF handler to provide BREACH protection.
*
* @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 {
mshima marked this conversation as resolved.
Show resolved Hide resolved
private final CsrfTokenRequestHandler delegate = 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);
}

@Override
public String resolveCsrfTokenValue(HttpServletRequest request, CsrfToken csrfToken) {
/*
* If the request contains a request header, use CsrfTokenRequestAttributeHandler
* to resolve the CsrfToken. This applies when a single-page application includes
* the header value automatically, which was obtained via a cookie containing the
* raw CsrfToken.
*/
if (StringUtils.hasText(request.getHeader(csrfToken.getHeaderName()))) {
return super.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);
}
}
<%_ } _%>
}
Loading