Skip to content

Commit fb322f9

Browse files
committed
Create CsrfCustomizer for SPA configuration (#14149)
1 parent 39b195c commit fb322f9

File tree

2 files changed

+156
-61
lines changed

2 files changed

+156
-61
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package org.springframework.security.config.annotation.web.configurers;
2+
3+
import jakarta.servlet.http.HttpServletRequest;
4+
import jakarta.servlet.http.HttpServletResponse;
5+
import org.springframework.security.config.Customizer;
6+
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
7+
import org.springframework.security.web.csrf.*;
8+
import org.springframework.util.StringUtils;
9+
10+
import java.util.function.Supplier;
11+
12+
public class CsrfCustomizer {
13+
public static Customizer<CsrfConfigurer<HttpSecurity>> spaDefaults() {
14+
return (csrf) -> csrf
15+
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
16+
.csrfTokenRequestHandler(new SpaCsrfTokenRequestHandler());
17+
}
18+
19+
private static class SpaCsrfTokenRequestHandler implements CsrfTokenRequestHandler {
20+
private final CsrfTokenRequestHandler plain = new CsrfTokenRequestAttributeHandler();
21+
private final CsrfTokenRequestHandler xor = new XorCsrfTokenRequestAttributeHandler();
22+
23+
@Override
24+
public void handle(HttpServletRequest request, HttpServletResponse response, Supplier<CsrfToken> csrfToken) {
25+
/*
26+
* Always use XorCsrfTokenRequestAttributeHandler to provide BREACH protection of
27+
* the CsrfToken when it is rendered in the response body.
28+
*/
29+
this.xor.handle(request, response, csrfToken);
30+
/*
31+
* Render the token value to a cookie by causing the deferred token to be loaded.
32+
*/
33+
csrfToken.get();
34+
}
35+
36+
@Override
37+
public String resolveCsrfTokenValue(HttpServletRequest request, CsrfToken csrfToken) {
38+
String headerValue = request.getHeader(csrfToken.getHeaderName());
39+
/*
40+
* If the request contains a request header, use CsrfTokenRequestAttributeHandler
41+
* to resolve the CsrfToken. This applies when a single-page application includes
42+
* the header value automatically, which was obtained via a cookie containing the
43+
* raw CsrfToken.
44+
*
45+
* In all other cases (e.g. if the request contains a request parameter), use
46+
* XorCsrfTokenRequestAttributeHandler to resolve the CsrfToken. This applies
47+
* when a server-side rendered form includes the _csrf request parameter as a
48+
* hidden input.
49+
*/
50+
return (StringUtils.hasText(headerValue) ? this.plain : this.xor).resolveCsrfTokenValue(request, csrfToken);
51+
}
52+
}
53+
}

0 commit comments

Comments
 (0)