mirror of
				https://github.com/spring-projects/spring-security.git
				synced 2025-11-04 00:28:54 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			520 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			520 lines
		
	
	
		
			16 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.
 | 
						|
 | 
						|
[NOTE]
 | 
						|
====
 | 
						|
Some examples of where it should be unnecessary to read the session include endpoints marked `permitAll()` such as static assets, static HTML pages, single-page applications hosted under the same domain/server, etc.
 | 
						|
====
 | 
						|
 | 
						|
In Spring Security 6, the default is that the lookup of the `CsrfToken` will be deferred until it is needed.
 | 
						|
 | 
						|
[NOTE]
 | 
						|
====
 | 
						|
The `CsrfToken` is needed whenever a request is made with an HTTP verb that would change the state of the application.
 | 
						|
This is covered in detail in xref:features/exploits/csrf.adoc#csrf-protection-read-only[Safe Methods Must be Read-only].
 | 
						|
Additionally, it is needed by any request that renders the token to the response, such as a web page with a `<form>` tag that includes a hidden `<input>` for the CSRF token.
 | 
						|
====
 | 
						|
 | 
						|
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`
 | 
						|
[tabs]
 | 
						|
======
 | 
						|
Java::
 | 
						|
+
 | 
						|
[source,java,role="primary"]
 | 
						|
----
 | 
						|
@Bean
 | 
						|
public SecurityFilterChain 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"/>
 | 
						|
----
 | 
						|
======
 | 
						|
 | 
						|
[NOTE]
 | 
						|
====
 | 
						|
When the `CsrfToken` is deferred (the default in Spring Security 6), some applications may break due to the fact that they were designed with non-deferred CSRF tokens.
 | 
						|
See <<servlet-defer-loading-csrf-token-opt-out,Opt-out Steps>> below for more information.
 | 
						|
====
 | 
						|
 | 
						|
[[servlet-defer-loading-csrf-token-opt-out]]
 | 
						|
=== Opt-out Steps
 | 
						|
 | 
						|
If configuring the `CsrfToken` to be deferred gives you trouble, take a look at these scenarios for optimal opt out behavior:
 | 
						|
 | 
						|
==== I am using a Single-Page Application with `CookieCsrfTokenRepository`
 | 
						|
 | 
						|
If you are using a single-page app (SPA) to connect to a backend protected by Spring Security along with `CookieCsrfTokenRepository.withHttpOnlyFalse()`, you may find that the CSRF token is no longer returned to your application as a cookie on the first request to the server.
 | 
						|
 | 
						|
In this case, you have several options for restoring the behavior your client-side application expects.
 | 
						|
One option is to add a `Filter` that eagerly renders the `CsrfToken` to the response regardless of which request is made first, like so:
 | 
						|
 | 
						|
.Add a `Filter` to return a cookie on the response
 | 
						|
[tabs]
 | 
						|
======
 | 
						|
Java::
 | 
						|
+
 | 
						|
[source,java,role="primary"]
 | 
						|
----
 | 
						|
@Bean
 | 
						|
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
 | 
						|
	CookieCsrfTokenRepository tokenRepository = CookieCsrfTokenRepository.withHttpOnlyFalse();
 | 
						|
	CsrfTokenRequestAttributeHandler requestHandler = new CsrfTokenRequestAttributeHandler();
 | 
						|
	// set the name of the attribute the CsrfToken will be populated on
 | 
						|
	requestHandler.setCsrfRequestAttributeName("_csrf");
 | 
						|
	http
 | 
						|
		// ...
 | 
						|
		.csrf((csrf) -> csrf
 | 
						|
			.csrfTokenRepository(tokenRepository)
 | 
						|
			.csrfTokenRequestHandler(requestHandler)
 | 
						|
		)
 | 
						|
		.addFilterAfter(new CsrfCookieFilter(), BasicAuthenticationFilter.class);
 | 
						|
 | 
						|
	return http.build();
 | 
						|
}
 | 
						|
 | 
						|
private static final class CsrfCookieFilter extends OncePerRequestFilter {
 | 
						|
 | 
						|
	@Override
 | 
						|
	protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
 | 
						|
			throws ServletException, IOException {
 | 
						|
		CsrfToken csrfToken = (CsrfToken) request.getAttribute(CsrfToken.class.getName());
 | 
						|
		// Render the token value to a cookie by causing the deferred token to be loaded
 | 
						|
		csrfToken.getToken();
 | 
						|
 | 
						|
		filterChain.doFilter(request, response);
 | 
						|
	}
 | 
						|
 | 
						|
}
 | 
						|
----
 | 
						|
 | 
						|
Kotlin::
 | 
						|
+
 | 
						|
[source,kotlin,role="secondary"]
 | 
						|
----
 | 
						|
@Bean
 | 
						|
open fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
 | 
						|
	val tokenRepository = CookieCsrfTokenRepository.withHttpOnlyFalse()
 | 
						|
	val requestHandler = CsrfTokenRequestAttributeHandler()
 | 
						|
	// set the name of the attribute the CsrfToken will be populated on
 | 
						|
	requestHandler.setCsrfRequestAttributeName("_csrf")
 | 
						|
	http {
 | 
						|
		csrf {
 | 
						|
			csrfTokenRepository = tokenRepository
 | 
						|
			csrfTokenRequestHandler = requestHandler
 | 
						|
		}
 | 
						|
		addFilterAfter<BasicAuthenticationFilter>(CsrfCookieFilter())
 | 
						|
	}
 | 
						|
	return http.build()
 | 
						|
}
 | 
						|
 | 
						|
class CsrfCookieFilter : OncePerRequestFilter() {
 | 
						|
 | 
						|
	override fun doFilterInternal(request: HttpServletRequest, response: HttpServletResponse, filterChain: FilterChain) {
 | 
						|
		val csrfToken = request.getAttribute(CsrfToken::class.java.name) as CsrfToken
 | 
						|
		// Render the token value to a cookie by causing the deferred token to be loaded
 | 
						|
		csrfToken.token
 | 
						|
 | 
						|
		filterChain.doFilter(request, response)
 | 
						|
	}
 | 
						|
 | 
						|
}
 | 
						|
----
 | 
						|
======
 | 
						|
 | 
						|
The option above does not require changes to the single-page application, but does cause the `CsrfToken` to be loaded on every request.
 | 
						|
If you do not wish to add a `Filter` to eagerly load tokens on every request, additional options are listed below.
 | 
						|
 | 
						|
==== I am using a Single-Page Application with `HttpSessionCsrfTokenRepository`
 | 
						|
 | 
						|
If you are using sessions, your application will benefit from deferred tokens.
 | 
						|
Instead of opting out, another option is to add a new `@RestController` with a `/csrf` endpoint, like so:
 | 
						|
 | 
						|
.Add a `/csrf` endpoint
 | 
						|
[tabs]
 | 
						|
======
 | 
						|
Java::
 | 
						|
+
 | 
						|
[source,java,role="primary"]
 | 
						|
----
 | 
						|
@RestController
 | 
						|
public class CsrfController {
 | 
						|
 | 
						|
    @GetMapping("/csrf")
 | 
						|
    public CsrfToken csrf(CsrfToken csrfToken) {
 | 
						|
        return csrfToken;
 | 
						|
    }
 | 
						|
 | 
						|
}
 | 
						|
----
 | 
						|
 | 
						|
Kotlin::
 | 
						|
+
 | 
						|
[source,kotlin,role="secondary"]
 | 
						|
----
 | 
						|
@RestController
 | 
						|
class CsrfController {
 | 
						|
 | 
						|
    @GetMapping("/csrf")
 | 
						|
    fun csrf(csrfToken: CsrfToken): CsrfToken {
 | 
						|
        return csrfToken
 | 
						|
    }
 | 
						|
 | 
						|
}
 | 
						|
----
 | 
						|
======
 | 
						|
 | 
						|
[NOTE]
 | 
						|
====
 | 
						|
You may consider adding `.requestMatchers("/csrf").permitAll()` if the endpoint above is required prior to authenticating with the server.
 | 
						|
====
 | 
						|
 | 
						|
The `/csrf` endpoint would need to be consumed by the client-side application in order to bootstrap the application for subsequent requests.
 | 
						|
 | 
						|
[NOTE]
 | 
						|
====
 | 
						|
Instructions for calling the `/csrf` endpoint on application launch are specific to your client-side framework and therefore outside the scope of this document.
 | 
						|
====
 | 
						|
 | 
						|
[NOTE]
 | 
						|
====
 | 
						|
While this requires changes to your single-page application, the benefit is that the CSRF token is only loaded once and the token can continue to be deferred.
 | 
						|
This approach works particularly well with applications that use `HttpSessionCsrfTokenRepository` and do benefit from deferred tokens by allowing the `HttpSession` not to be read on every request.
 | 
						|
====
 | 
						|
 | 
						|
If you simply wish to opt out of deferred tokens altogether, that option is listed next.
 | 
						|
 | 
						|
==== I need to opt out of deferred tokens for another reason
 | 
						|
 | 
						|
If deferred tokens break your application for another reason, then you can explicitly opt into the 5.8 defaults using the following configuration:
 | 
						|
 | 
						|
.Explicit Configure `CsrfToken` with 5.8 Defaults
 | 
						|
[tabs]
 | 
						|
======
 | 
						|
Java::
 | 
						|
+
 | 
						|
[source,java,role="primary"]
 | 
						|
----
 | 
						|
@Bean
 | 
						|
public SecurityFilterChain securityFilterChain(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 securityFilterChain(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>
 | 
						|
----
 | 
						|
======
 | 
						|
 | 
						|
[NOTE]
 | 
						|
====
 | 
						|
By setting the `csrfRequestAttributeName` to `null`, the `CsrfToken` must first be loaded to determine what attribute name to use.
 | 
						|
This causes the `CsrfToken` to be loaded on every request.
 | 
						|
====
 | 
						|
 | 
						|
== 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
 | 
						|
[tabs]
 | 
						|
======
 | 
						|
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
 | 
						|
[tabs]
 | 
						|
======
 | 
						|
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"/>
 | 
						|
----
 | 
						|
======
 | 
						|
 | 
						|
This is the RECOMMENDED way to configure Spring Security to work with a client-side application that uses cookie values, because it continues to allow the response to return a randomized value for the CSRF token in case the application returns HTML or other responses that could be vulnerable to BREACH without your knowledge.
 | 
						|
 | 
						|
[NOTE]
 | 
						|
====
 | 
						|
BREACH protection works to protect the token when it is included in a response body that can be GZIP compressed, which generally does not include headers and cookies.
 | 
						|
====
 | 
						|
 | 
						|
[TIP]
 | 
						|
====
 | 
						|
Any token value returned by the server can be used successfully by the client-side application because the underlying (raw) CSRF token does not change.
 | 
						|
It is not required for an AngularJS (or similar) application to refresh the CSRF token before/after every request.
 | 
						|
====
 | 
						|
 | 
						|
If you simply wish to opt out of CSRF BREACH protection altogether, that option is listed next.
 | 
						|
 | 
						|
==== 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
 | 
						|
[tabs]
 | 
						|
======
 | 
						|
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
 | 
						|
[tabs]
 | 
						|
======
 | 
						|
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"/>
 | 
						|
----
 | 
						|
======
 |