Skip to content

Commit d72b57d

Browse files
committed
Processed review comments and updated documentation
Signed-off-by: Felix Hagemans <[email protected]>
1 parent 8d09a9a commit d72b57d

File tree

4 files changed

+145
-227
lines changed

4 files changed

+145
-227
lines changed

config/src/main/java/org/springframework/security/config/annotation/web/configurers/CsrfConfigurer.java

+60
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,11 @@
1919
import java.util.ArrayList;
2020
import java.util.LinkedHashMap;
2121
import java.util.List;
22+
import java.util.function.Supplier;
2223

2324
import io.micrometer.observation.ObservationRegistry;
2425
import jakarta.servlet.http.HttpServletRequest;
26+
import jakarta.servlet.http.HttpServletResponse;
2527

2628
import org.springframework.context.ApplicationContext;
2729
import org.springframework.security.access.AccessDeniedException;
@@ -34,20 +36,25 @@
3436
import org.springframework.security.web.access.DelegatingAccessDeniedHandler;
3537
import org.springframework.security.web.access.ObservationMarkingAccessDeniedHandler;
3638
import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy;
39+
import org.springframework.security.web.csrf.CookieCsrfTokenRepository;
3740
import org.springframework.security.web.csrf.CsrfAuthenticationStrategy;
3841
import org.springframework.security.web.csrf.CsrfFilter;
3942
import org.springframework.security.web.csrf.CsrfLogoutHandler;
43+
import org.springframework.security.web.csrf.CsrfToken;
4044
import org.springframework.security.web.csrf.CsrfTokenRepository;
45+
import org.springframework.security.web.csrf.CsrfTokenRequestAttributeHandler;
4146
import org.springframework.security.web.csrf.CsrfTokenRequestHandler;
4247
import org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository;
4348
import org.springframework.security.web.csrf.MissingCsrfTokenException;
49+
import org.springframework.security.web.csrf.XorCsrfTokenRequestAttributeHandler;
4450
import org.springframework.security.web.session.InvalidSessionAccessDeniedHandler;
4551
import org.springframework.security.web.session.InvalidSessionStrategy;
4652
import org.springframework.security.web.util.matcher.AndRequestMatcher;
4753
import org.springframework.security.web.util.matcher.NegatedRequestMatcher;
4854
import org.springframework.security.web.util.matcher.OrRequestMatcher;
4955
import org.springframework.security.web.util.matcher.RequestMatcher;
5056
import org.springframework.util.Assert;
57+
import org.springframework.util.StringUtils;
5158

5259
/**
5360
* Adds
@@ -214,6 +221,21 @@ public CsrfConfigurer<H> sessionAuthenticationStrategy(
214221
return this;
215222
}
216223

224+
/**
225+
* <p>
226+
* Sensible CSRF defaults when used in combination with a single page application.
227+
* Creates a cookie-based token repository and a custom request handler to resolve the
228+
* actual token value instead of the encoded token.
229+
* </p>
230+
* @return the {@link CsrfConfigurer} for further customizations
231+
* @since 7.0
232+
*/
233+
public CsrfConfigurer<H> spa() {
234+
this.csrfTokenRepository = CookieCsrfTokenRepository.withHttpOnlyFalse();
235+
this.requestHandler = new SpaCsrfTokenRequestHandler();
236+
return this;
237+
}
238+
217239
@SuppressWarnings("unchecked")
218240
@Override
219241
public void configure(H http) {
@@ -375,4 +397,42 @@ protected IgnoreCsrfProtectionRegistry chainRequestMatchers(List<RequestMatcher>
375397

376398
}
377399

400+
private static class SpaCsrfTokenRequestHandler implements CsrfTokenRequestHandler {
401+
402+
private final CsrfTokenRequestAttributeHandler plain = new CsrfTokenRequestAttributeHandler();
403+
404+
private final CsrfTokenRequestAttributeHandler xor = new XorCsrfTokenRequestAttributeHandler();
405+
406+
SpaCsrfTokenRequestHandler() {
407+
this.xor.setCsrfRequestAttributeName(null);
408+
}
409+
410+
@Override
411+
public void handle(HttpServletRequest request, HttpServletResponse response, Supplier<CsrfToken> csrfToken) {
412+
/*
413+
* Always use XorCsrfTokenRequestAttributeHandler to provide BREACH protection
414+
* of the CsrfToken when it is rendered in the response body.
415+
*/
416+
this.xor.handle(request, response, csrfToken);
417+
}
418+
419+
@Override
420+
public String resolveCsrfTokenValue(HttpServletRequest request, CsrfToken csrfToken) {
421+
String headerValue = request.getHeader(csrfToken.getHeaderName());
422+
/*
423+
* If the request contains a request header, use
424+
* CsrfTokenRequestAttributeHandler to resolve the CsrfToken. This applies
425+
* when a single-page application includes the header value automatically,
426+
* which was obtained via a cookie containing the raw CsrfToken.
427+
*
428+
* In all other cases (e.g. if the request contains a request parameter), use
429+
* XorCsrfTokenRequestAttributeHandler to resolve the CsrfToken. This applies
430+
* when a server-side rendered form includes the _csrf request parameter as a
431+
* hidden input.
432+
*/
433+
return (StringUtils.hasText(headerValue) ? this.plain : this.xor).resolveCsrfTokenValue(request, csrfToken);
434+
}
435+
436+
}
437+
378438
}

config/src/main/java/org/springframework/security/config/annotation/web/configurers/CsrfCustomizer.java

-57
This file was deleted.

0 commit comments

Comments
 (0)