246 lines
7.2 KiB
Plaintext
246 lines
7.2 KiB
Plaintext
= Exploit Protection Migrations
|
|
|
|
The following steps relate to changes around how to configure CSRF.
|
|
|
|
== Defer Loading CsrfToken
|
|
|
|
In Spring Security 5, the default behavior is that the `CsrfToken` will be loaded on every request.
|
|
This means that in a typical setup, the `HttpSession` must be read for every request even if it is unnecessary.
|
|
|
|
In Spring Security 6, the default is that the lookup of the `CsrfToken` will be deferred until it is needed.
|
|
|
|
To opt into the new Spring Security 6 default, the following configuration can be used.
|
|
|
|
[[servlet-opt-in-defer-loading-csrf-token]]
|
|
.Defer Loading `CsrfToken`
|
|
====
|
|
.Java
|
|
[source,java,role="primary"]
|
|
----
|
|
@Bean
|
|
DefaultSecurityFilterChain springSecurity(HttpSecurity http) throws Exception {
|
|
CsrfTokenRequestAttributeHandler requestHandler = new CsrfTokenRequestAttributeHandler();
|
|
// set the name of the attribute the CsrfToken will be populated on
|
|
requestHandler.setCsrfRequestAttributeName("_csrf");
|
|
http
|
|
// ...
|
|
.csrf((csrf) -> csrf
|
|
.csrfTokenRequestHandler(requestHandler)
|
|
);
|
|
return http.build();
|
|
}
|
|
----
|
|
|
|
.Kotlin
|
|
[source,kotlin,role="secondary"]
|
|
----
|
|
@Bean
|
|
open fun springSecurity(http: HttpSecurity): SecurityFilterChain {
|
|
val requestHandler = CsrfTokenRequestAttributeHandler()
|
|
// set the name of the attribute the CsrfToken will be populated on
|
|
requestHandler.setCsrfRequestAttributeName("_csrf")
|
|
http {
|
|
csrf {
|
|
csrfTokenRequestHandler = requestHandler
|
|
}
|
|
}
|
|
return http.build()
|
|
}
|
|
----
|
|
|
|
.XML
|
|
[source,xml,role="secondary"]
|
|
----
|
|
<http>
|
|
<!-- ... -->
|
|
<csrf request-handler-ref="requestHandler"/>
|
|
</http>
|
|
<b:bean id="requestHandler"
|
|
class="org.springframework.security.web.csrf.CsrfTokenRequestAttributeHandler"
|
|
p:csrfRequestAttributeName="_csrf"/>
|
|
----
|
|
====
|
|
|
|
If this breaks your application, then you can explicitly opt into the 5.8 defaults using the following configuration:
|
|
|
|
.Explicit Configure `CsrfToken` with 5.8 Defaults
|
|
====
|
|
.Java
|
|
[source,java,role="primary"]
|
|
----
|
|
@Bean
|
|
DefaultSecurityFilterChain springSecurity(HttpSecurity http) throws Exception {
|
|
CsrfTokenRequestAttributeHandler requestHandler = new CsrfTokenRequestAttributeHandler();
|
|
// set the name of the attribute the CsrfToken will be populated on
|
|
requestHandler.setCsrfRequestAttributeName(null);
|
|
http
|
|
// ...
|
|
.csrf((csrf) -> csrf
|
|
.csrfTokenRequestHandler(requestHandler)
|
|
);
|
|
return http.build();
|
|
}
|
|
----
|
|
|
|
.Kotlin
|
|
[source,kotlin,role="secondary"]
|
|
----
|
|
@Bean
|
|
open fun springSecurity(http: HttpSecurity): SecurityFilterChain {
|
|
val requestHandler = CsrfTokenRequestAttributeHandler()
|
|
// set the name of the attribute the CsrfToken will be populated on
|
|
requestHandler.setCsrfRequestAttributeName(null)
|
|
http {
|
|
csrf {
|
|
csrfTokenRequestHandler = requestHandler
|
|
}
|
|
}
|
|
return http.build()
|
|
}
|
|
----
|
|
|
|
.XML
|
|
[source,xml,role="secondary"]
|
|
----
|
|
<http>
|
|
<!-- ... -->
|
|
<csrf request-handler-ref="requestHandler"/>
|
|
</http>
|
|
<b:bean id="requestHandler"
|
|
class="org.springframework.security.web.csrf.CsrfTokenRequestAttributeHandler">
|
|
<b:property name="csrfRequestAttributeName">
|
|
<b:null/>
|
|
</b:property>
|
|
</b:bean>
|
|
----
|
|
====
|
|
|
|
== Protect against CSRF BREACH
|
|
|
|
If the steps for <<Defer Loading CsrfToken>> work for you, then you can also opt into Spring Security 6's default support for BREACH protection of the `CsrfToken` using the following configuration:
|
|
|
|
.`CsrfToken` BREACH Protection
|
|
====
|
|
.Java
|
|
[source,java,role="primary"]
|
|
----
|
|
@Bean
|
|
DefaultSecurityFilterChain springSecurity(HttpSecurity http) throws Exception {
|
|
XorCsrfTokenRequestAttributeHandler requestHandler = new XorCsrfTokenRequestAttributeHandler();
|
|
// set the name of the attribute the CsrfToken will be populated on
|
|
requestHandler.setCsrfRequestAttributeName("_csrf");
|
|
http
|
|
// ...
|
|
.csrf((csrf) -> csrf
|
|
.csrfTokenRequestHandler(requestHandler)
|
|
);
|
|
return http.build();
|
|
}
|
|
----
|
|
|
|
.Kotlin
|
|
[source,kotlin,role="secondary"]
|
|
----
|
|
@Bean
|
|
open fun springSecurity(http: HttpSecurity): SecurityFilterChain {
|
|
val requestHandler = XorCsrfTokenRequestAttributeHandler()
|
|
// set the name of the attribute the CsrfToken will be populated on
|
|
requestHandler.setCsrfRequestAttributeName("_csrf")
|
|
http {
|
|
csrf {
|
|
csrfTokenRequestHandler = requestHandler
|
|
}
|
|
}
|
|
return http.build()
|
|
}
|
|
----
|
|
|
|
.XML
|
|
[source,xml,role="secondary"]
|
|
----
|
|
<http>
|
|
<!-- ... -->
|
|
<csrf request-handler-ref="requestHandler"/>
|
|
</http>
|
|
<b:bean id="requestHandler"
|
|
class="org.springframework.security.web.csrf.XorCsrfTokenRequestAttributeHandler"
|
|
p:csrfRequestAttributeName="_csrf"/>
|
|
----
|
|
====
|
|
|
|
[[servlet-csrf-breach-opt-out]]
|
|
=== Opt-out Steps
|
|
|
|
If configuring CSRF BREACH protection gives you trouble, take a look at these scenarios for optimal opt out behavior:
|
|
|
|
==== I am using AngularJS or another Javascript framework
|
|
|
|
If you are using AngularJS and the https://angular.io/api/common/http/HttpClientXsrfModule[HttpClientXsrfModule] (or a similar module in another framework) along with `CookieCsrfTokenRepository.withHttpOnlyFalse()`, you may find that automatic support no longer works.
|
|
|
|
In this case, you can configure Spring Security to validate the raw `CsrfToken` from the cookie while keeping CSRF BREACH protection of the response using a custom `CsrfTokenRequestHandler` with delegation, like so:
|
|
|
|
.Configure `CsrfToken` BREACH Protection to validate raw tokens
|
|
====
|
|
.Java
|
|
[source,java,role="primary"]
|
|
----
|
|
@Bean
|
|
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
|
|
CookieCsrfTokenRepository tokenRepository = CookieCsrfTokenRepository.withHttpOnlyFalse();
|
|
XorCsrfTokenRequestAttributeHandler delegate = new XorCsrfTokenRequestAttributeHandler();
|
|
// set the name of the attribute the CsrfToken will be populated on
|
|
delegate.setCsrfRequestAttributeName("_csrf");
|
|
// Use only the handle() method of XorCsrfTokenRequestAttributeHandler and the
|
|
// default implementation of resolveCsrfTokenValue() from CsrfTokenRequestHandler
|
|
CsrfTokenRequestHandler requestHandler = delegate::handle;
|
|
http
|
|
// ...
|
|
.csrf((csrf) -> csrf
|
|
.csrfTokenRepository(tokenRepository)
|
|
.csrfTokenRequestHandler(requestHandler)
|
|
);
|
|
|
|
return http.build();
|
|
}
|
|
----
|
|
|
|
.Kotlin
|
|
[source,kotlin,role="secondary"]
|
|
----
|
|
@Bean
|
|
open fun springSecurity(http: HttpSecurity): SecurityFilterChain {
|
|
val tokenRepository = CookieCsrfTokenRepository.withHttpOnlyFalse()
|
|
val delegate = XorCsrfTokenRequestAttributeHandler()
|
|
// set the name of the attribute the CsrfToken will be populated on
|
|
delegate.setCsrfRequestAttributeName("_csrf")
|
|
// Use only the handle() method of XorCsrfTokenRequestAttributeHandler and the
|
|
// default implementation of resolveCsrfTokenValue() from CsrfTokenRequestHandler
|
|
val requestHandler = CsrfTokenRequestHandler(delegate::handle)
|
|
http {
|
|
csrf {
|
|
csrfTokenRepository = tokenRepository
|
|
csrfTokenRequestHandler = requestHandler
|
|
}
|
|
}
|
|
return http.build()
|
|
}
|
|
----
|
|
|
|
.XML
|
|
[source,xml,role="secondary"]
|
|
----
|
|
<http>
|
|
<!-- ... -->
|
|
<csrf token-repository-ref="tokenRepository"
|
|
request-handler-ref="requestHandler"/>
|
|
</http>
|
|
<b:bean id="tokenRepository"
|
|
class="org.springframework.security.web.csrf.CookieCsrfTokenRepository"
|
|
p:cookieHttpOnly="false"/>
|
|
----
|
|
====
|
|
|
|
==== I need to opt out of CSRF BREACH protection for another reason
|
|
|
|
If CSRF BREACH protection does not work for you for another reason, you can opt out using the configuration from the <<servlet-opt-in-defer-loading-csrf-token>> section.
|