= 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.

== CSRF BREACH with WebSocket support

If the steps for <<Protect against CSRF BREACH>> work for normal HTTP requests and you are using xref:servlet/integrations/websocket.adoc[WebSocket Security] support, then you can also opt into Spring Security 6's default support for BREACH protection of the `CsrfToken` with xref:servlet/integrations/websocket.adoc#websocket-sameorigin-csrf[Stomp headers].

.WebSocket Security BREACH Protection
====
.Java
[source,java,role="primary"]
----
@Bean
ChannelInterceptor csrfChannelInterceptor() {
	return new XorCsrfChannelInterceptor();
}
----

.Kotlin
[source,kotlin,role="secondary"]
----
@Bean
open fun csrfChannelInterceptor(): ChannelInterceptor {
	return XorCsrfChannelInterceptor()
}
----

.XML
[source,xml,role="secondary"]
----
<b:bean id="csrfChannelInterceptor"
	class="org.springframework.security.messaging.web.csrf.XorCsrfChannelInterceptor"/>
----
====

If configuring CSRF BREACH protection for WebSocket Security gives you trouble, you can configure the 5.8 default using the following configuration:

.Configure WebSocket Security with 5.8 default
====
.Java
[source,java,role="primary"]
----
@Bean
ChannelInterceptor csrfChannelInterceptor() {
	return new CsrfChannelInterceptor();
}
----

.Kotlin
[source,kotlin,role="secondary"]
----
@Bean
open fun csrfChannelInterceptor(): ChannelInterceptor {
	return CsrfChannelInterceptor()
}
----

.XML
[source,xml,role="secondary"]
----
<b:bean id="csrfChannelInterceptor"
	class="org.springframework.security.messaging.web.csrf.CsrfChannelInterceptor"/>
----
====
