mirror of
				https://github.com/spring-projects/spring-security.git
				synced 2025-10-31 06:38:42 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			1651 lines
		
	
	
		
			56 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			1651 lines
		
	
	
		
			56 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
| [[servlet-csrf]]
 | ||
| = Cross Site Request Forgery (CSRF)
 | ||
| :figures: servlet/exploits
 | ||
| 
 | ||
| In an application where end users can xref:servlet/authentication/index.adoc[log in], it is important to consider how to protect against xref:features/exploits/csrf.adoc#csrf[Cross Site Request Forgery (CSRF)].
 | ||
| 
 | ||
| Spring Security protects against CSRF attacks by default for xref:features/exploits/csrf.adoc#csrf-protection-read-only[unsafe HTTP methods], such as a POST request, so no additional code is necessary.
 | ||
| You can specify the default configuration explicitly using the following:
 | ||
| 
 | ||
| [[csrf-configuration]]
 | ||
| .Configure CSRF Protection
 | ||
| [tabs]
 | ||
| ======
 | ||
| Java::
 | ||
| +
 | ||
| [source,java,role="primary"]
 | ||
| ----
 | ||
| @Configuration
 | ||
| @EnableWebSecurity
 | ||
| public class SecurityConfig {
 | ||
| 
 | ||
| 	@Bean
 | ||
| 	public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
 | ||
| 		http
 | ||
| 			// ...
 | ||
| 			.csrf(Customizer.withDefaults());
 | ||
| 		return http.build();
 | ||
| 	}
 | ||
| }
 | ||
| ----
 | ||
| 
 | ||
| Kotlin::
 | ||
| +
 | ||
| [source,kotlin,role="secondary"]
 | ||
| ----
 | ||
| import org.springframework.security.config.annotation.web.invoke
 | ||
| 
 | ||
| @Configuration
 | ||
| @EnableWebSecurity
 | ||
| class SecurityConfig {
 | ||
| 
 | ||
|     @Bean
 | ||
|     open fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
 | ||
|         http {
 | ||
|             // ...
 | ||
|             csrf { }
 | ||
|         }
 | ||
|         return http.build()
 | ||
|     }
 | ||
| }
 | ||
| ----
 | ||
| 
 | ||
| XML::
 | ||
| +
 | ||
| [source,xml,role="secondary"]
 | ||
| ----
 | ||
| <http>
 | ||
| 	<!-- ... -->
 | ||
| 	<csrf/>
 | ||
| </http>
 | ||
| ----
 | ||
| ======
 | ||
| 
 | ||
| To learn more about CSRF protection for your application, consider the following use cases:
 | ||
| 
 | ||
| * I want to <<csrf-components,understand CSRF protection's components>>
 | ||
| * I need to <<migrating-to-spring-security-6,migrate an application from Spring Security 5 to 6>>
 | ||
| * I want to <<csrf-token-repository-cookie,store the `CsrfToken` in a cookie>> instead of <<csrf-token-repository-httpsession,the session>>
 | ||
| * I want to <<csrf-token-repository-custom,store the `CsrfToken` in a custom location>>
 | ||
| * I want to <<deferred-csrf-token-opt-out,opt-out of deferred tokens>>
 | ||
| * I want to <<csrf-token-request-handler-opt-out-of-breach,opt-out of BREACH protection>>
 | ||
| * I need guidance integrating <<csrf-integration-form,Thymeleaf, JSPs or another view technology>> with the backend
 | ||
| * I need guidance integrating <<csrf-integration-javascript,Angular or another JavaScript framework>> with the backend
 | ||
| * I need guidance integrating <<csrf-integration-mobile,a mobile application or another client>> with the backend
 | ||
| * I need guidance on <<csrf-access-denied-handler,handling errors>>
 | ||
| * I want to <<csrf-testing,test CSRF protection>>
 | ||
| * I need guidance on <<disable-csrf,disabling CSRF protection>>
 | ||
| 
 | ||
| [[csrf-components]]
 | ||
| == Understanding CSRF Protection's Components
 | ||
| 
 | ||
| CSRF protection is provided by several components that are composed within the {security-api-url}org/springframework/security/web/csrf/CsrfFilter.html[`CsrfFilter`]:
 | ||
| 
 | ||
| .`CsrfFilter` Components
 | ||
| [.invert-dark]
 | ||
| image::{figures}/csrf.png[]
 | ||
| 
 | ||
| CSRF protection is divided into two parts:
 | ||
| 
 | ||
| 1. Make the {security-api-url}org/springframework/security/web/csrf/CsrfToken.html[`CsrfToken`] available to the application by delegating to the <<csrf-token-request-handler,`CsrfTokenRequestHandler`>>.
 | ||
| 2. Determine if the request requires CSRF protection, load and validate the token, and <<csrf-access-denied-handler,handle `AccessDeniedException`>>.
 | ||
| 
 | ||
| .`CsrfFilter` Processing
 | ||
| [.invert-dark]
 | ||
| image::{figures}/csrf-processing.png[]
 | ||
| 
 | ||
| * image:{icondir}/number_1.png[] First, the {security-api-url}org/springframework/security/web/csrf/DeferredCsrfToken.html[`DeferredCsrfToken`] is loaded, which holds a reference to the <<csrf-token-repository,`CsrfTokenRepository`>> so that the persisted `CsrfToken` can be loaded later (in image:{icondir}/number_4.png[]).
 | ||
| * image:{icondir}/number_2.png[] Second, a `Supplier<CsrfToken>` (created from `DeferredCsrfToken`) is given to the <<csrf-token-request-handler,`CsrfTokenRequestHandler`>>, which is responsible for populating a request attribute to make the `CsrfToken` available to the rest of the application.
 | ||
| * image:{icondir}/number_3.png[] Next, the main CSRF protection processing begins and checks if the current request requires CSRF protection. If not required, the filter chain is continued and processing ends.
 | ||
| * image:{icondir}/number_4.png[] If CSRF protection is required, the persisted `CsrfToken` is finally loaded from the `DeferredCsrfToken`.
 | ||
| * image:{icondir}/number_5.png[] Continuing, the actual CSRF token provided by the client (if any) is resolved using the <<csrf-token-request-handler,`CsrfTokenRequestHandler`>>.
 | ||
| * image:{icondir}/number_6.png[] The actual CSRF token is compared against the persisted `CsrfToken`. If valid, the filter chain is continued and processing ends.
 | ||
| * image:{icondir}/number_7.png[] If the actual CSRF token is invalid (or missing), an `AccessDeniedException` is passed to the <<csrf-access-denied-handler,`AccessDeniedHandler`>> and processing ends.
 | ||
| 
 | ||
| [[migrating-to-spring-security-6]]
 | ||
| == Migrating to Spring Security 6
 | ||
| 
 | ||
| When migrating from Spring Security 5 to 6, there are a few changes that may impact your application.
 | ||
| The following is an overview of the aspects of CSRF protection that have changed in Spring Security 6:
 | ||
| 
 | ||
| * Loading of the `CsrfToken` is now <<deferred-csrf-token,deferred by default>> to improve performance by no longer requiring the session to be loaded on every request.
 | ||
| * The `CsrfToken` now includes <<csrf-token-request-handler-breach,randomness on every request by default>> to protect the CSRF token from a https://en.wikipedia.org/wiki/BREACH[BREACH] attack.
 | ||
| 
 | ||
| [TIP]
 | ||
| ====
 | ||
| The changes in Spring Security 6 require additional configuration for single-page applications, and as such you may find the <<csrf-integration-javascript-spa>> section particularly useful.
 | ||
| ====
 | ||
| 
 | ||
| See the https://docs.spring.io/spring-security/reference/5.8/migration/servlet/exploits.html[Exploit Protection] section of the https://docs.spring.io/spring-security/reference/5.8/migration/index.html[Migration] chapter for more information on migrating a Spring Security 5 application.
 | ||
| 
 | ||
| [[csrf-token-repository]]
 | ||
| == Persisting the `CsrfToken`
 | ||
| 
 | ||
| The `CsrfToken` is persisted using a `CsrfTokenRepository`.
 | ||
| 
 | ||
| By default, the <<csrf-token-repository-httpsession,`HttpSessionCsrfTokenRepository`>> is used for storing tokens in a session.
 | ||
| Spring Security also provides the <<csrf-token-repository-cookie,`CookieCsrfTokenRepository`>> for storing tokens in a cookie.
 | ||
| You can also specify <<csrf-token-repository-custom,your own implementation>> to store tokens wherever you like.
 | ||
| 
 | ||
| [[csrf-token-repository-httpsession]]
 | ||
| === Using the `HttpSessionCsrfTokenRepository`
 | ||
| 
 | ||
| By default, Spring Security stores the expected CSRF token in the `HttpSession` by using {security-api-url}org/springframework/security/web/csrf/HttpSessionCsrfTokenRepository.html[`HttpSessionCsrfTokenRepository`], so no additional code is necessary.
 | ||
| 
 | ||
| The `HttpSessionCsrfTokenRepository` reads the token from a session (whether in-memory, cache, or database). If you need to access the session attribute directly, please first configure the session attribute name using `HttpSessionCsrfTokenRepository#setSessionAttributeName`.
 | ||
| 
 | ||
| You can specify the default configuration explicitly using the following configuration:
 | ||
| 
 | ||
| [[csrf-token-repository-httpsession-configuration]]
 | ||
| .Configure `HttpSessionCsrfTokenRepository`
 | ||
| [tabs]
 | ||
| ======
 | ||
| Java::
 | ||
| +
 | ||
| [source,java,role="primary"]
 | ||
| ----
 | ||
| @Configuration
 | ||
| @EnableWebSecurity
 | ||
| public class SecurityConfig {
 | ||
| 
 | ||
| 	@Bean
 | ||
| 	public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
 | ||
| 		http
 | ||
| 			// ...
 | ||
| 			.csrf((csrf) -> csrf
 | ||
| 				.csrfTokenRepository(new HttpSessionCsrfTokenRepository())
 | ||
| 			);
 | ||
| 		return http.build();
 | ||
| 	}
 | ||
| }
 | ||
| ----
 | ||
| 
 | ||
| Kotlin::
 | ||
| +
 | ||
| [source,kotlin,role="secondary"]
 | ||
| ----
 | ||
| import org.springframework.security.config.annotation.web.invoke
 | ||
| 
 | ||
| @Configuration
 | ||
| @EnableWebSecurity
 | ||
| class SecurityConfig {
 | ||
| 
 | ||
|     @Bean
 | ||
|     open fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
 | ||
|         http {
 | ||
|             // ...
 | ||
|             csrf {
 | ||
|                 csrfTokenRepository = HttpSessionCsrfTokenRepository()
 | ||
|             }
 | ||
|         }
 | ||
|         return http.build()
 | ||
|     }
 | ||
| }
 | ||
| ----
 | ||
| 
 | ||
| XML::
 | ||
| +
 | ||
| [source,xml,role="secondary"]
 | ||
| ----
 | ||
| <http>
 | ||
| 	<!-- ... -->
 | ||
| 	<csrf token-repository-ref="tokenRepository"/>
 | ||
| </http>
 | ||
| <b:bean id="tokenRepository"
 | ||
| 	class="org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository"/>
 | ||
| ----
 | ||
| ======
 | ||
| 
 | ||
| [[csrf-token-repository-cookie]]
 | ||
| === Using the `CookieCsrfTokenRepository`
 | ||
| 
 | ||
| You can persist the `CsrfToken` in a cookie to <<csrf-integration-javascript,support a JavaScript-based application>> using the {security-api-url}org/springframework/security/web/csrf/CookieCsrfTokenRepository.html[`CookieCsrfTokenRepository`].
 | ||
| 
 | ||
| The `CookieCsrfTokenRepository` writes to a cookie named `XSRF-TOKEN` and reads it from an HTTP request header named `X-XSRF-TOKEN` or the request parameter `_csrf` by default.
 | ||
| These defaults come from Angular and its predecessor https://docs.angularjs.org/api/ng/service/$http#cross-site-request-forgery-xsrf-protection[AngularJS].
 | ||
| 
 | ||
| [TIP]
 | ||
| ====
 | ||
| See the https://angular.io/guide/http-security-xsrf-protection[Cross-Site Request Forgery (XSRF) protection] guide and the https://angular.io/api/common/http/HttpClientXsrfModule[HttpClientXsrfModule] for more recent information on this topic.
 | ||
| ====
 | ||
| 
 | ||
| You can configure the `CookieCsrfTokenRepository` using the following configuration:
 | ||
| 
 | ||
| [[csrf-token-repository-cookie-configuration]]
 | ||
| .Configure `CookieCsrfTokenRepository`
 | ||
| [tabs]
 | ||
| ======
 | ||
| Java::
 | ||
| +
 | ||
| [source,java,role="primary"]
 | ||
| ----
 | ||
| @Configuration
 | ||
| @EnableWebSecurity
 | ||
| public class SecurityConfig {
 | ||
| 
 | ||
| 	@Bean
 | ||
| 	public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
 | ||
| 		http
 | ||
| 			// ...
 | ||
| 			.csrf((csrf) -> csrf
 | ||
| 				.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
 | ||
| 			);
 | ||
| 		return http.build();
 | ||
| 	}
 | ||
| }
 | ||
| ----
 | ||
| 
 | ||
| Kotlin::
 | ||
| +
 | ||
| [source,kotlin,role="secondary"]
 | ||
| ----
 | ||
| import org.springframework.security.config.annotation.web.invoke
 | ||
| 
 | ||
| @Configuration
 | ||
| @EnableWebSecurity
 | ||
| class SecurityConfig {
 | ||
| 
 | ||
|     @Bean
 | ||
|     open fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
 | ||
|         http {
 | ||
|             // ...
 | ||
|             csrf {
 | ||
|                 csrfTokenRepository = CookieCsrfTokenRepository.withHttpOnlyFalse()
 | ||
|             }
 | ||
|         }
 | ||
|         return http.build()
 | ||
|     }
 | ||
| }
 | ||
| ----
 | ||
| 
 | ||
| XML::
 | ||
| +
 | ||
| [source,xml,role="secondary"]
 | ||
| ----
 | ||
| <http>
 | ||
| 	<!-- ... -->
 | ||
| 	<csrf token-repository-ref="tokenRepository"/>
 | ||
| </http>
 | ||
| <b:bean id="tokenRepository"
 | ||
| 	class="org.springframework.security.web.csrf.CookieCsrfTokenRepository"
 | ||
| 	p:cookieHttpOnly="false"/>
 | ||
| ----
 | ||
| ======
 | ||
| 
 | ||
| [NOTE]
 | ||
| ====
 | ||
| The example explicitly sets `HttpOnly` to `false`.
 | ||
| This is necessary to let JavaScript frameworks (such as Angular) read it.
 | ||
| If you do not need the ability to read the cookie with JavaScript directly, we _recommend_ omitting `HttpOnly` (by using `new CookieCsrfTokenRepository()` instead) to improve security.
 | ||
| ====
 | ||
| 
 | ||
| [[csrf-token-repository-custom]]
 | ||
| === Customizing the `CsrfTokenRepository`
 | ||
| 
 | ||
| There can be cases where you want to implement a custom {security-api-url}org/springframework/security/web/csrf/CsrfTokenRepository.html[`CsrfTokenRepository`].
 | ||
| 
 | ||
| Once you've implemented the `CsrfTokenRepository` interface, you can configure Spring Security to use it with the following configuration:
 | ||
| 
 | ||
| [[csrf-token-repository-custom-configuration]]
 | ||
| .Configure Custom `CsrfTokenRepository`
 | ||
| [tabs]
 | ||
| ======
 | ||
| Java::
 | ||
| +
 | ||
| [source,java,role="primary"]
 | ||
| ----
 | ||
| @Configuration
 | ||
| @EnableWebSecurity
 | ||
| public class SecurityConfig {
 | ||
| 
 | ||
| 	@Bean
 | ||
| 	public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
 | ||
| 		http
 | ||
| 			// ...
 | ||
| 			.csrf((csrf) -> csrf
 | ||
| 				.csrfTokenRepository(new CustomCsrfTokenRepository())
 | ||
| 			);
 | ||
| 		return http.build();
 | ||
| 	}
 | ||
| }
 | ||
| ----
 | ||
| 
 | ||
| Kotlin::
 | ||
| +
 | ||
| [source,kotlin,role="secondary"]
 | ||
| ----
 | ||
| import org.springframework.security.config.annotation.web.invoke
 | ||
| 
 | ||
| @Configuration
 | ||
| @EnableWebSecurity
 | ||
| class SecurityConfig {
 | ||
| 
 | ||
|     @Bean
 | ||
|     open fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
 | ||
|         http {
 | ||
|             // ...
 | ||
|             csrf {
 | ||
|                 csrfTokenRepository = CustomCsrfTokenRepository()
 | ||
|             }
 | ||
|         }
 | ||
|         return http.build()
 | ||
|     }
 | ||
| }
 | ||
| ----
 | ||
| 
 | ||
| XML::
 | ||
| +
 | ||
| [source,xml,role="secondary"]
 | ||
| ----
 | ||
| <http>
 | ||
| 	<!-- ... -->
 | ||
| 	<csrf token-repository-ref="tokenRepository"/>
 | ||
| </http>
 | ||
| <b:bean id="tokenRepository"
 | ||
| 	class="example.CustomCsrfTokenRepository"/>
 | ||
| ----
 | ||
| ======
 | ||
| 
 | ||
| [[csrf-token-request-handler]]
 | ||
| == Handling the `CsrfToken`
 | ||
| 
 | ||
| The `CsrfToken` is made available to an application using a `CsrfTokenRequestHandler`.
 | ||
| This component is also responsible for resolving the `CsrfToken` from HTTP headers or request parameters.
 | ||
| 
 | ||
| By default, the <<csrf-token-request-handler-breach,`XorCsrfTokenRequestAttributeHandler`>> is used for providing https://en.wikipedia.org/wiki/BREACH[BREACH] protection of the `CsrfToken`.
 | ||
| Spring Security also provides the <<csrf-token-request-handler-plain,`CsrfTokenRequestAttributeHandler`>> for opting out of BREACH protection.
 | ||
| You can also specify <<csrf-token-request-handler-custom,your own implementation>> to customize the strategy for handling and resolving tokens.
 | ||
| 
 | ||
| [[csrf-token-request-handler-breach]]
 | ||
| === Using the `XorCsrfTokenRequestAttributeHandler` (BREACH)
 | ||
| 
 | ||
| The `XorCsrfTokenRequestAttributeHandler` makes the `CsrfToken` available as an `HttpServletRequest` attribute called `_csrf`, and additionally provides protection for https://en.wikipedia.org/wiki/BREACH[BREACH].
 | ||
| 
 | ||
| [NOTE]
 | ||
| ====
 | ||
| The `CsrfToken` is also made available as a request attribute using the name `CsrfToken.class.getName()`.
 | ||
| This name is not configurable, but the name `_csrf` can be changed using `XorCsrfTokenRequestAttributeHandler#setCsrfRequestAttributeName`.
 | ||
| ====
 | ||
| 
 | ||
| This implementation also resolves the token value from the request as either a request header (one of <<csrf-token-repository-httpsession,`X-CSRF-TOKEN`>> or <<csrf-token-repository-cookie,`X-XSRF-TOKEN`>> by default) or a request parameter (`_csrf` by default).
 | ||
| 
 | ||
| [NOTE]
 | ||
| ====
 | ||
| BREACH protection is provided by encoding randomness into the CSRF token value to ensure the returned `CsrfToken` changes on every request.
 | ||
| When the token is later resolved as a header value or request parameter, it is decoded to obtain the raw token which is then compared to the <<csrf-token-repository,persisted `CsrfToken`>>.
 | ||
| ====
 | ||
| 
 | ||
| Spring Security protects the CSRF token from a BREACH attack by default, so no additional code is necessary.
 | ||
| You can specify the default configuration explicitly using the following configuration:
 | ||
| 
 | ||
| [[csrf-token-request-handler-breach-configuration]]
 | ||
| .Configure BREACH protection
 | ||
| [tabs]
 | ||
| ======
 | ||
| Java::
 | ||
| +
 | ||
| [source,java,role="primary"]
 | ||
| ----
 | ||
| @Configuration
 | ||
| @EnableWebSecurity
 | ||
| public class SecurityConfig {
 | ||
| 
 | ||
| 	@Bean
 | ||
| 	public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
 | ||
| 		http
 | ||
| 			// ...
 | ||
| 			.csrf((csrf) -> csrf
 | ||
| 				.csrfTokenRequestHandler(new XorCsrfTokenRequestAttributeHandler())
 | ||
| 			);
 | ||
| 		return http.build();
 | ||
| 	}
 | ||
| }
 | ||
| ----
 | ||
| 
 | ||
| Kotlin::
 | ||
| +
 | ||
| [source,kotlin,role="secondary"]
 | ||
| ----
 | ||
| import org.springframework.security.config.annotation.web.invoke
 | ||
| 
 | ||
| @Configuration
 | ||
| @EnableWebSecurity
 | ||
| class SecurityConfig {
 | ||
| 
 | ||
|     @Bean
 | ||
|     open fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
 | ||
|         http {
 | ||
|             // ...
 | ||
|             csrf {
 | ||
|                 csrfTokenRequestHandler = XorCsrfTokenRequestAttributeHandler()
 | ||
|             }
 | ||
|         }
 | ||
|         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"/>
 | ||
| ----
 | ||
| ======
 | ||
| 
 | ||
| [[csrf-token-request-handler-plain]]
 | ||
| === Using the `CsrfTokenRequestAttributeHandler`
 | ||
| 
 | ||
| The `CsrfTokenRequestAttributeHandler` makes the `CsrfToken` available as an `HttpServletRequest` attribute called `_csrf`.
 | ||
| 
 | ||
| [NOTE]
 | ||
| ====
 | ||
| The `CsrfToken` is also made available as a request attribute using the name `CsrfToken.class.getName()`.
 | ||
| This name is not configurable, but the name `_csrf` can be changed using `CsrfTokenRequestAttributeHandler#setCsrfRequestAttributeName`.
 | ||
| ====
 | ||
| 
 | ||
| This implementation also resolves the token value from the request as either a request header (one of <<csrf-token-repository-httpsession,`X-CSRF-TOKEN`>> or <<csrf-token-repository-cookie,`X-XSRF-TOKEN`>> by default) or a request parameter (`_csrf` by default).
 | ||
| 
 | ||
| [[csrf-token-request-handler-opt-out-of-breach]]
 | ||
| The primary use of `CsrfTokenRequestAttributeHandler` is to opt-out of BREACH protection of the `CsrfToken`, which can be configured using the following configuration:
 | ||
| 
 | ||
| .Opt-out of BREACH protection
 | ||
| [tabs]
 | ||
| ======
 | ||
| Java::
 | ||
| +
 | ||
| [source,java,role="primary"]
 | ||
| ----
 | ||
| @Configuration
 | ||
| @EnableWebSecurity
 | ||
| public class SecurityConfig {
 | ||
| 
 | ||
| 	@Bean
 | ||
| 	public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
 | ||
| 		http
 | ||
| 			// ...
 | ||
| 			.csrf((csrf) -> csrf
 | ||
| 				.csrfTokenRequestHandler(new CsrfTokenRequestAttributeHandler())
 | ||
| 			);
 | ||
| 		return http.build();
 | ||
| 	}
 | ||
| }
 | ||
| ----
 | ||
| 
 | ||
| Kotlin::
 | ||
| +
 | ||
| [source,kotlin,role="secondary"]
 | ||
| ----
 | ||
| import org.springframework.security.config.annotation.web.invoke
 | ||
| 
 | ||
| @Configuration
 | ||
| @EnableWebSecurity
 | ||
| class SecurityConfig {
 | ||
| 
 | ||
|     @Bean
 | ||
|     open fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
 | ||
|         http {
 | ||
|             // ...
 | ||
|             csrf {
 | ||
|                 csrfTokenRequestHandler = CsrfTokenRequestAttributeHandler()
 | ||
|             }
 | ||
|         }
 | ||
|         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"/>
 | ||
| ----
 | ||
| ======
 | ||
| 
 | ||
| [[csrf-token-request-handler-custom]]
 | ||
| === Customizing the `CsrfTokenRequestHandler`
 | ||
| 
 | ||
| You can implement the `CsrfTokenRequestHandler` interface to customize the strategy for handling and resolving tokens.
 | ||
| 
 | ||
| [TIP]
 | ||
| ====
 | ||
| The `CsrfTokenRequestHandler` interface is a `@FunctionalInterface` that can be implemented using a lambda expression to customize request handling.
 | ||
| You will need to implement the full interface to customize how tokens are resolved from the request.
 | ||
| See <<csrf-integration-javascript-spa-configuration>> for an example that uses delegation to implement a custom strategy for handling and resolving tokens.
 | ||
| ====
 | ||
| 
 | ||
| Once you've implemented the `CsrfTokenRequestHandler` interface, you can configure Spring Security to use it with the following configuration:
 | ||
| 
 | ||
| [[csrf-token-request-handler-custom-configuration]]
 | ||
| .Configure Custom `CsrfTokenRequestHandler`
 | ||
| [tabs]
 | ||
| ======
 | ||
| Java::
 | ||
| +
 | ||
| [source,java,role="primary"]
 | ||
| ----
 | ||
| @Configuration
 | ||
| @EnableWebSecurity
 | ||
| public class SecurityConfig {
 | ||
| 
 | ||
| 	@Bean
 | ||
| 	public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
 | ||
| 		http
 | ||
| 			// ...
 | ||
| 			.csrf((csrf) -> csrf
 | ||
| 				.csrfTokenRequestHandler(new CustomCsrfTokenRequestHandler())
 | ||
| 			);
 | ||
| 		return http.build();
 | ||
| 	}
 | ||
| }
 | ||
| ----
 | ||
| 
 | ||
| Kotlin::
 | ||
| +
 | ||
| [source,kotlin,role="secondary"]
 | ||
| ----
 | ||
| import org.springframework.security.config.annotation.web.invoke
 | ||
| 
 | ||
| @Configuration
 | ||
| @EnableWebSecurity
 | ||
| class SecurityConfig {
 | ||
| 
 | ||
|     @Bean
 | ||
|     open fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
 | ||
|         http {
 | ||
|             // ...
 | ||
|             csrf {
 | ||
|                 csrfTokenRequestHandler = CustomCsrfTokenRequestHandler()
 | ||
|             }
 | ||
|         }
 | ||
|         return http.build()
 | ||
|     }
 | ||
| }
 | ||
| ----
 | ||
| 
 | ||
| XML::
 | ||
| +
 | ||
| [source,xml,role="secondary"]
 | ||
| ----
 | ||
| <http>
 | ||
| 	<!-- ... -->
 | ||
| 	<csrf request-handler-ref="requestHandler"/>
 | ||
| </http>
 | ||
| <b:bean id="requestHandler"
 | ||
| 	class="example.CustomCsrfTokenRequestHandler"/>
 | ||
| ----
 | ||
| ======
 | ||
| 
 | ||
| [[deferred-csrf-token]]
 | ||
| == Deferred Loading of the `CsrfToken`
 | ||
| 
 | ||
| By default, Spring Security defers loading of the `CsrfToken` until it is needed.
 | ||
| 
 | ||
| [NOTE]
 | ||
| ====
 | ||
| The `CsrfToken` is needed whenever a request is made with an xref:features/exploits/csrf.adoc#csrf-protection-read-only[unsafe HTTP method], such as a POST.
 | ||
| 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.
 | ||
| ====
 | ||
| 
 | ||
| Because Spring Security also stores the `CsrfToken` in the `HttpSession` by default, deferred CSRF tokens can improve performance by not requiring the session to be loaded on every request.
 | ||
| 
 | ||
| [[deferred-csrf-token-opt-out]]
 | ||
| In the event that you want to opt-out of deferred tokens and cause the `CsrfToken` to be loaded on every request, you can do so with the following configuration:
 | ||
| 
 | ||
| [[deferred-csrf-token-opt-out-configuration]]
 | ||
| .Opt-out of Deferred CSRF Tokens
 | ||
| [tabs]
 | ||
| ======
 | ||
| Java::
 | ||
| +
 | ||
| [source,java,role="primary"]
 | ||
| ----
 | ||
| @Configuration
 | ||
| @EnableWebSecurity
 | ||
| public class SecurityConfig {
 | ||
| 
 | ||
| 	@Bean
 | ||
| 	public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
 | ||
| 		XorCsrfTokenRequestAttributeHandler requestHandler = new XorCsrfTokenRequestAttributeHandler();
 | ||
| 		// 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"]
 | ||
| ----
 | ||
| import org.springframework.security.config.annotation.web.invoke
 | ||
| 
 | ||
| @Configuration
 | ||
| @EnableWebSecurity
 | ||
| class SecurityConfig {
 | ||
| 
 | ||
|     @Bean
 | ||
|     open fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
 | ||
|         val requestHandler = XorCsrfTokenRequestAttributeHandler()
 | ||
|         // 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.
 | ||
| ====
 | ||
| 
 | ||
| 
 | ||
| [[csrf-integration]]
 | ||
| == Integrating with CSRF Protection
 | ||
| 
 | ||
| For the xref:features/exploits/csrf.adoc#csrf-protection-stp[synchronizer token pattern] to protect against CSRF attacks, we must include the actual CSRF token in the HTTP request.
 | ||
| This must be included in a part of the request (a form parameter, an HTTP header, or other part) that is not automatically included in the HTTP request by the browser.
 | ||
| 
 | ||
| The following sections describe the various ways a frontend or client application can integrate with a CSRF-protected backend application:
 | ||
| 
 | ||
| * <<csrf-integration-form>>
 | ||
| * <<csrf-integration-javascript>>
 | ||
| * <<csrf-integration-mobile>>
 | ||
| 
 | ||
| [[csrf-integration-form]]
 | ||
| === HTML Forms
 | ||
| 
 | ||
| To submit an HTML form, the CSRF token must be included in the form as a hidden input.
 | ||
| For example, the rendered HTML might look like:
 | ||
| 
 | ||
| .CSRF Token in HTML Form
 | ||
| [source,html]
 | ||
| ----
 | ||
| <input type="hidden"
 | ||
| 	name="_csrf"
 | ||
| 	value="4bfd1575-3ad1-4d21-96c7-4ef2d9f86721"/>
 | ||
| ----
 | ||
| 
 | ||
| The following view technologies automatically include the actual CSRF token in a form that has an unsafe HTTP method, such as a POST:
 | ||
| 
 | ||
| * https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#mvc-view-jsp-formtaglib[Spring’s form tag library]
 | ||
| * https://www.thymeleaf.org/doc/tutorials/2.1/thymeleafspring.html#integration-with-requestdatavalueprocessor[Thymeleaf]
 | ||
| * Any other view technology that integrates with {spring-framework-api-url}org/springframework/web/servlet/support/RequestDataValueProcessor.html[`RequestDataValueProcessor`] (via {security-api-url}org/springframework/security/web/servlet/support/csrf/CsrfRequestDataValueProcessor.html[`CsrfRequestDataValueProcessor`])
 | ||
| * You can also include the token yourself via the xref:servlet/integrations/jsp-taglibs.adoc#taglibs-csrfinput[csrfInput] tag
 | ||
| 
 | ||
| If these options are not available, you can take advantage of the fact that the `CsrfToken` is exposed as an <<csrf-token-request-handler,`HttpServletRequest` attribute named `_csrf`>>.
 | ||
| The following example does this with a JSP:
 | ||
| 
 | ||
| .CSRF Token in HTML Form with Request Attribute
 | ||
| [source,xml]
 | ||
| ----
 | ||
| <c:url var="logoutUrl" value="/logout"/>
 | ||
| <form action="${logoutUrl}"
 | ||
| 	method="post">
 | ||
| <input type="submit"
 | ||
| 	value="Log out" />
 | ||
| <input type="hidden"
 | ||
| 	name="${_csrf.parameterName}"
 | ||
| 	value="${_csrf.token}"/>
 | ||
| </form>
 | ||
| ----
 | ||
| 
 | ||
| [[csrf-integration-javascript]]
 | ||
| === JavaScript Applications
 | ||
| 
 | ||
| JavaScript applications typically use JSON instead of HTML.
 | ||
| If you use JSON, you can submit the CSRF token within an HTTP request header instead of a request parameter.
 | ||
| 
 | ||
| In order to obtain the CSRF token, you can configure Spring Security to store the expected CSRF token <<csrf-token-repository-cookie,in a cookie>>.
 | ||
| By storing the expected token in a cookie, JavaScript frameworks such as https://angular.io/api/common/http/HttpClientXsrfModule[Angular] can automatically include the actual CSRF token as an HTTP request header.
 | ||
| 
 | ||
| [TIP]
 | ||
| ====
 | ||
| There are special considerations for BREACH protection and deferred tokens when integrating a single-page application (SPA) with Spring Security's CSRF protection.
 | ||
| A full configuration example is provided in the <<csrf-integration-javascript-spa,next section>>.
 | ||
| ====
 | ||
| 
 | ||
| You can read about different types of JavaScript applications in the following sections:
 | ||
| 
 | ||
| * <<csrf-integration-javascript-spa>>
 | ||
| * <<csrf-integration-javascript-mpa>>
 | ||
| * <<csrf-integration-javascript-other>>
 | ||
| 
 | ||
| [[csrf-integration-javascript-spa]]
 | ||
| ==== Single-Page Applications
 | ||
| 
 | ||
| There are special considerations for integrating a single-page application (SPA) with Spring Security's CSRF protection.
 | ||
| 
 | ||
| Recall that Spring Security provides <<csrf-token-request-handler-breach,BREACH protection of the `CsrfToken`>> by default.
 | ||
| When storing the expected CSRF token <<csrf-token-repository-cookie,in a cookie>>, JavaScript applications will only have access to the plain token value and _will not_ have access to the encoded value.
 | ||
| A <<csrf-token-request-handler-custom,customized request handler>> for resolving the actual token value will need to be provided.
 | ||
| 
 | ||
| In addition, the cookie storing the CSRF token will be cleared upon authentication success and logout success.
 | ||
| Spring Security defers loading a new CSRF token by default, and additional work is required to return a fresh cookie.
 | ||
| 
 | ||
| [NOTE]
 | ||
| ====
 | ||
| Refreshing the token after authentication success and logout success is required because the {security-api-url}org/springframework/security/web/csrf/CsrfAuthenticationStrategy.html[`CsrfAuthenticationStrategy`] and {security-api-url}org/springframework/security/web/csrf/CsrfLogoutHandler.html[`CsrfLogoutHandler`] will clear the previous token.
 | ||
| The client application will not be able to perform an unsafe HTTP request, such as a POST, without obtaining a fresh token.
 | ||
| ====
 | ||
| 
 | ||
| In order to easily integrate a single-page application with Spring Security, the following configuration can be used:
 | ||
| 
 | ||
| [[csrf-integration-javascript-spa-configuration]]
 | ||
| .Configure CSRF for Single-Page Application
 | ||
| [tabs]
 | ||
| ======
 | ||
| Java::
 | ||
| +
 | ||
| [source,java,role="primary"]
 | ||
| ----
 | ||
| @Configuration
 | ||
| @EnableWebSecurity
 | ||
| public class SecurityConfig {
 | ||
| 
 | ||
| 	@Bean
 | ||
| 	public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
 | ||
| 		http
 | ||
| 			// ...
 | ||
| 			.csrf((csrf) -> csrf
 | ||
| 				.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())   // <1>
 | ||
| 				.csrfTokenRequestHandler(new SpaCsrfTokenRequestHandler())            // <2>
 | ||
| 			)
 | ||
| 			.addFilterAfter(new CsrfCookieFilter(), BasicAuthenticationFilter.class); // <3>
 | ||
| 		return http.build();
 | ||
| 	}
 | ||
| }
 | ||
| 
 | ||
| final class SpaCsrfTokenRequestHandler extends CsrfTokenRequestAttributeHandler {
 | ||
| 	private final CsrfTokenRequestHandler delegate = new XorCsrfTokenRequestAttributeHandler();
 | ||
| 
 | ||
| 	@Override
 | ||
| 	public void handle(HttpServletRequest request, HttpServletResponse response, Supplier<CsrfToken> csrfToken) {
 | ||
| 		/*
 | ||
| 		 * Always use XorCsrfTokenRequestAttributeHandler to provide BREACH protection of
 | ||
| 		 * the CsrfToken when it is rendered in the response body.
 | ||
| 		 */
 | ||
| 		this.delegate.handle(request, response, csrfToken);
 | ||
| 	}
 | ||
| 
 | ||
| 	@Override
 | ||
| 	public String resolveCsrfTokenValue(HttpServletRequest request, CsrfToken csrfToken) {
 | ||
| 		/*
 | ||
| 		 * If the request contains a request header, use CsrfTokenRequestAttributeHandler
 | ||
| 		 * to resolve the CsrfToken. This applies when a single-page application includes
 | ||
| 		 * the header value automatically, which was obtained via a cookie containing the
 | ||
| 		 * raw CsrfToken.
 | ||
| 		 */
 | ||
| 		if (StringUtils.hasText(request.getHeader(csrfToken.getHeaderName()))) {
 | ||
| 			return super.resolveCsrfTokenValue(request, csrfToken);
 | ||
| 		}
 | ||
| 		/*
 | ||
| 		 * In all other cases (e.g. if the request contains a request parameter), use
 | ||
| 		 * XorCsrfTokenRequestAttributeHandler to resolve the CsrfToken. This applies
 | ||
| 		 * when a server-side rendered form includes the _csrf request parameter as a
 | ||
| 		 * hidden input.
 | ||
| 		 */
 | ||
| 		return this.delegate.resolveCsrfTokenValue(request, csrfToken);
 | ||
| 	}
 | ||
| }
 | ||
| 
 | ||
| final class CsrfCookieFilter extends OncePerRequestFilter {
 | ||
| 
 | ||
| 	@Override
 | ||
| 	protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
 | ||
| 			throws ServletException, IOException {
 | ||
| 		CsrfToken csrfToken = (CsrfToken) request.getAttribute("_csrf");
 | ||
| 		// 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"]
 | ||
| ----
 | ||
| import org.springframework.security.config.annotation.web.invoke
 | ||
| 
 | ||
| @Configuration
 | ||
| @EnableWebSecurity
 | ||
| class SecurityConfig {
 | ||
| 
 | ||
|     @Bean
 | ||
|     open fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
 | ||
|         http {
 | ||
|             // ...
 | ||
|             csrf {
 | ||
|                 csrfTokenRepository = CookieCsrfTokenRepository.withHttpOnlyFalse()    // <1>
 | ||
|                 csrfTokenRequestHandler = SpaCsrfTokenRequestHandler()                 // <2>
 | ||
|             }
 | ||
|         }
 | ||
|         http.addFilterAfter(CsrfCookieFilter(), BasicAuthenticationFilter::class.java) // <3>
 | ||
|         return http.build()
 | ||
|     }
 | ||
| }
 | ||
| 
 | ||
| class SpaCsrfTokenRequestHandler : CsrfTokenRequestAttributeHandler() {
 | ||
|     private val delegate: CsrfTokenRequestHandler = XorCsrfTokenRequestAttributeHandler()
 | ||
| 
 | ||
|     override fun handle(request: HttpServletRequest, response: HttpServletResponse, csrfToken: Supplier<CsrfToken>) {
 | ||
|         /*
 | ||
|          * Always use XorCsrfTokenRequestAttributeHandler to provide BREACH protection of
 | ||
|          * the CsrfToken when it is rendered in the response body.
 | ||
|          */
 | ||
|         delegate.handle(request, response, csrfToken)
 | ||
|     }
 | ||
| 
 | ||
|     override fun resolveCsrfTokenValue(request: HttpServletRequest, csrfToken: CsrfToken): String? {
 | ||
|         /*
 | ||
|          * If the request contains a request header, use CsrfTokenRequestAttributeHandler
 | ||
|          * to resolve the CsrfToken. This applies when a single-page application includes
 | ||
|          * the header value automatically, which was obtained via a cookie containing the
 | ||
|          * raw CsrfToken.
 | ||
|          */
 | ||
|         return if (StringUtils.hasText(request.getHeader(csrfToken.headerName))) {
 | ||
|             super.resolveCsrfTokenValue(request, csrfToken)
 | ||
|         } else {
 | ||
|             /*
 | ||
|              * In all other cases (e.g. if the request contains a request parameter), use
 | ||
|              * XorCsrfTokenRequestAttributeHandler to resolve the CsrfToken. This applies
 | ||
|              * when a server-side rendered form includes the _csrf request parameter as a
 | ||
|              * hidden input.
 | ||
|              */
 | ||
|             delegate.resolveCsrfTokenValue(request, csrfToken)
 | ||
|         }
 | ||
|     }
 | ||
| }
 | ||
| 
 | ||
| class CsrfCookieFilter : OncePerRequestFilter() {
 | ||
| 
 | ||
|     @Throws(ServletException::class, IOException::class)
 | ||
|     override fun doFilterInternal(request: HttpServletRequest, response: HttpServletResponse, filterChain: FilterChain) {
 | ||
|         val csrfToken = request.getAttribute("_csrf") as CsrfToken
 | ||
|         // Render the token value to a cookie by causing the deferred token to be loaded
 | ||
|         csrfToken.token
 | ||
|         filterChain.doFilter(request, response)
 | ||
|     }
 | ||
| }
 | ||
| ----
 | ||
| 
 | ||
| XML::
 | ||
| +
 | ||
| [source,xml,role="secondary"]
 | ||
| ----
 | ||
| <http>
 | ||
| 	<!-- ... -->
 | ||
| 	<csrf
 | ||
| 		token-repository-ref="tokenRepository"                        <1>
 | ||
| 		request-handler-ref="requestHandler"/>                        <2>
 | ||
| 	<custom-filter ref="csrfCookieFilter" after="BASIC_AUTH_FILTER"/> <3>
 | ||
| </http>
 | ||
| <b:bean id="tokenRepository"
 | ||
| 	class="org.springframework.security.web.csrf.CookieCsrfTokenRepository"
 | ||
| 	p:cookieHttpOnly="false"/>
 | ||
| <b:bean id="requestHandler"
 | ||
| 	class="example.SpaCsrfTokenRequestHandler"/>
 | ||
| <b:bean id="csrfCookieFilter"
 | ||
| 	class="example.CsrfCookieFilter"/>
 | ||
| ----
 | ||
| ======
 | ||
| 
 | ||
| <1> Configure `CookieCsrfTokenRepository` with `HttpOnly` set to `false` so the cookie can be read by the JavaScript application.
 | ||
| <2> Configure a custom `CsrfTokenRequestHandler` that resolves the CSRF token based on whether it is an HTTP request header (`X-XSRF-TOKEN`) or request parameter (`_csrf`).
 | ||
| <3> Configure a custom `Filter` to load the `CsrfToken` on every request, which will return a new cookie if needed.
 | ||
| 
 | ||
| [[csrf-integration-javascript-mpa]]
 | ||
| ==== Multi-Page Applications
 | ||
| 
 | ||
| For multi-page applications where JavaScript is loaded on each page, an alternative to exposing the CSRF token <<csrf-token-repository-cookie,in a cookie>> is to include the CSRF token within your `meta` tags.
 | ||
| The HTML might look something like this:
 | ||
| 
 | ||
| .CSRF Token in HTML Meta Tag
 | ||
| [source,html]
 | ||
| ----
 | ||
| <html>
 | ||
| <head>
 | ||
| 	<meta name="_csrf" content="4bfd1575-3ad1-4d21-96c7-4ef2d9f86721"/>
 | ||
| 	<meta name="_csrf_header" content="X-CSRF-TOKEN"/>
 | ||
| 	<!-- ... -->
 | ||
| </head>
 | ||
| <!-- ... -->
 | ||
| </html>
 | ||
| ----
 | ||
| 
 | ||
| In order to include the CSRF token in the request, you can take advantage of the fact that the `CsrfToken` is exposed as an <<csrf-token-request-handler,`HttpServletRequest` attribute named `_csrf`>>.
 | ||
| The following example does this with a JSP:
 | ||
| 
 | ||
| .CSRF Token in HTML Meta Tag with Request Attribute
 | ||
| [source,html]
 | ||
| ----
 | ||
| <html>
 | ||
| <head>
 | ||
| 	<meta name="_csrf" content="${_csrf.token}"/>
 | ||
| 	<!-- default header name is X-CSRF-TOKEN -->
 | ||
| 	<meta name="_csrf_header" content="${_csrf.headerName}"/>
 | ||
| 	<!-- ... -->
 | ||
| </head>
 | ||
| <!-- ... -->
 | ||
| </html>
 | ||
| ----
 | ||
| 
 | ||
| Once the meta tags contain the CSRF token, the JavaScript code can read the meta tags and include the CSRF token as a header.
 | ||
| If you use jQuery, you can do this with the following code:
 | ||
| 
 | ||
| .Include CSRF Token in AJAX Request
 | ||
| [source,javascript]
 | ||
| ----
 | ||
| $(function () {
 | ||
| 	var token = $("meta[name='_csrf']").attr("content");
 | ||
| 	var header = $("meta[name='_csrf_header']").attr("content");
 | ||
| 	$(document).ajaxSend(function(e, xhr, options) {
 | ||
| 		xhr.setRequestHeader(header, token);
 | ||
| 	});
 | ||
| });
 | ||
| ----
 | ||
| 
 | ||
| [[csrf-integration-javascript-other]]
 | ||
| ==== Other JavaScript Applications
 | ||
| 
 | ||
| Another option for JavaScript applications is to include the CSRF token in an HTTP response header.
 | ||
| 
 | ||
| One way to achieve this is through the use of a `@ControllerAdvice` with the xref:servlet/integrations/mvc.adoc#mvc-csrf-resolver[`CsrfTokenArgumentResolver`].
 | ||
| The following is an example of `@ControllerAdvice` that applies to all controller endpoints in the application:
 | ||
| 
 | ||
| [[controller-advice]]
 | ||
| .CSRF Token in HTTP Response Header
 | ||
| [tabs]
 | ||
| ======
 | ||
| Java::
 | ||
| +
 | ||
| [source,java,role="primary"]
 | ||
| ----
 | ||
| @ControllerAdvice
 | ||
| public class CsrfControllerAdvice {
 | ||
| 
 | ||
| 	@ModelAttribute
 | ||
| 	public void getCsrfToken(HttpServletResponse response, CsrfToken csrfToken) {
 | ||
| 		response.setHeader(csrfToken.getHeaderName(), csrfToken.getToken());
 | ||
| 	}
 | ||
| 
 | ||
| }
 | ||
| ----
 | ||
| 
 | ||
| Kotlin::
 | ||
| +
 | ||
| [source,kotlin,role="secondary"]
 | ||
| ----
 | ||
| @ControllerAdvice
 | ||
| class CsrfControllerAdvice {
 | ||
| 
 | ||
| 	@ModelAttribute
 | ||
| 	fun getCsrfToken(response: HttpServletResponse, csrfToken: CsrfToken) {
 | ||
| 		response.setHeader(csrfToken.headerName, csrfToken.token)
 | ||
| 	}
 | ||
| 
 | ||
| }
 | ||
| ----
 | ||
| ======
 | ||
| 
 | ||
| [NOTE]
 | ||
| ====
 | ||
| Because this `@ControllerAdvice` applies to all endpoints in the application, it will cause the CSRF token to be loaded on every request, which can negate the benefits of <<deferred-csrf-token,deferred tokens>> when using the <<csrf-token-repository-httpsession,`HttpSessionCsrfTokenRepository`>>.
 | ||
| However, this is not usually an issue when using the <<csrf-token-repository-cookie,`CookieCsrfTokenRepository`>>.
 | ||
| ====
 | ||
| 
 | ||
| [NOTE]
 | ||
| ====
 | ||
| It is important to remember that controller endpoints and controller advice are called _after_ the Spring Security filter chain.
 | ||
| This means that this `@ControllerAdvice` will only be applied if the request passes through the filter chain to your application.
 | ||
| See the configuration for <<csrf-integration-javascript-spa-configuration,single-page applications>> for an example of adding a filter to the filter chain for earlier access to the `HttpServletResponse`.
 | ||
| ====
 | ||
| 
 | ||
| The CSRF token will now be available in a response header (<<csrf-token-repository-httpsession,`X-CSRF-TOKEN`>> or <<csrf-token-repository-cookie,`X-XSRF-TOKEN`>> by default) for any custom endpoints the controller advice applies to.
 | ||
| Any request to the backend can be used to obtain the token from the response, and a subsequent request can include the token in a request header with the same name.
 | ||
| 
 | ||
| [[csrf-integration-mobile]]
 | ||
| === Mobile Applications
 | ||
| 
 | ||
| Like <<csrf-integration-javascript,JavaScript applications>>, mobile applications typically use JSON instead of HTML.
 | ||
| A backend application that _does not_ serve browser traffic may choose to <<disable-csrf,disable CSRF>>.
 | ||
| In that case, no additional work is required.
 | ||
| 
 | ||
| However, a backend application that also serves browser traffic and therefore _still requires_ CSRF protection may continue to store the `CsrfToken` <<csrf-token-repository-httpsession,in the session>> instead of <<csrf-token-repository-cookie,in a cookie>>.
 | ||
| 
 | ||
| In this case, a typical pattern for integrating with the backend is to expose a `/csrf` endpoint to allow the frontend (mobile or browser client) to request a CSRF token on demand.
 | ||
| The benefit of using this pattern is that the CSRF token <<deferred-csrf-token,can continue to be deferred>> and only needs to be loaded from the session when a request requires CSRF protection.
 | ||
| The use of a custom endpoint also means the client application can request that a new token be generated on demand (if necessary) by issuing an explicit request.
 | ||
| 
 | ||
| [TIP]
 | ||
| ====
 | ||
| This pattern can be used for any type of application that requires CSRF protection, not just mobile applications.
 | ||
| While this approach isn't typically required in those cases, it is another option for integrating with a CSRF-protected backend.
 | ||
| ====
 | ||
| 
 | ||
| The following is an example of the `/csrf` endpoint that makes use of the xref:servlet/integrations/mvc.adoc#mvc-csrf-resolver[`CsrfTokenArgumentResolver`]:
 | ||
| 
 | ||
| [[csrf-endpoint]]
 | ||
| .The `/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.
 | ||
| ====
 | ||
| 
 | ||
| This endpoint should be called to obtain a CSRF token when the application is launched or initialized (e.g. at load time), and also after authentication success and logout success.
 | ||
| 
 | ||
| [NOTE]
 | ||
| ====
 | ||
| Refreshing the token after authentication success and logout success is required because the {security-api-url}org/springframework/security/web/csrf/CsrfAuthenticationStrategy.html[`CsrfAuthenticationStrategy`] and {security-api-url}org/springframework/security/web/csrf/CsrfLogoutHandler.html[`CsrfLogoutHandler`] will clear the previous token.
 | ||
| The client application will not be able to perform an unsafe HTTP request, such as a POST, without obtaining a fresh token.
 | ||
| ====
 | ||
| 
 | ||
| Once you've obtained the CSRF token, you will need to include it as an HTTP request header (one of <<csrf-token-repository-httpsession,`X-CSRF-TOKEN`>> or <<csrf-token-repository-cookie,`X-XSRF-TOKEN`>> by default) yourself.
 | ||
| 
 | ||
| [[csrf-access-denied-handler]]
 | ||
| == Handle `AccessDeniedException`
 | ||
| 
 | ||
| To handle an `AccessDeniedException` such as `InvalidCsrfTokenException`, you can configure Spring Security to handle these exceptions in any way you like.
 | ||
| For example, you can configure a custom access denied page using the following configuration:
 | ||
| 
 | ||
| [[csrf-access-denied-handler-configuration]]
 | ||
| .Configure `AccessDeniedHandler`
 | ||
| [tabs]
 | ||
| ======
 | ||
| Java::
 | ||
| +
 | ||
| [source,java,role="primary"]
 | ||
| ----
 | ||
| @Configuration
 | ||
| @EnableWebSecurity
 | ||
| public class SecurityConfig {
 | ||
| 
 | ||
| 	@Bean
 | ||
| 	public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
 | ||
| 		http
 | ||
| 			// ...
 | ||
| 			.exceptionHandling((exceptionHandling) -> exceptionHandling
 | ||
| 				.accessDeniedPage("/access-denied")
 | ||
| 			);
 | ||
| 		return http.build();
 | ||
| 	}
 | ||
| }
 | ||
| ----
 | ||
| 
 | ||
| Kotlin::
 | ||
| +
 | ||
| [source,kotlin,role="secondary"]
 | ||
| ----
 | ||
| import org.springframework.security.config.annotation.web.invoke
 | ||
| 
 | ||
| @Configuration
 | ||
| @EnableWebSecurity
 | ||
| class SecurityConfig {
 | ||
| 
 | ||
|     @Bean
 | ||
|     open fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
 | ||
|         http {
 | ||
|             // ...
 | ||
|             exceptionHandling {
 | ||
|                 accessDeniedPage = "/access-denied"
 | ||
|             }
 | ||
|         }
 | ||
|         return http.build()
 | ||
|     }
 | ||
| }
 | ||
| ----
 | ||
| 
 | ||
| XML::
 | ||
| +
 | ||
| [source,xml,role="secondary"]
 | ||
| ----
 | ||
| <http>
 | ||
| 	<!-- ... -->
 | ||
| 	<access-denied-handler error-page="/access-denied"/>
 | ||
| </http>
 | ||
| ----
 | ||
| ======
 | ||
| 
 | ||
| [[csrf-testing]]
 | ||
| == CSRF Testing
 | ||
| 
 | ||
| You can use Spring Security's xref:servlet/test/mockmvc/setup.adoc[testing support] and xref:servlet/test/mockmvc/csrf.adoc[`CsrfRequestPostProcessor`] to test CSRF protection, like this:
 | ||
| 
 | ||
| [[csrf-testing-example]]
 | ||
| .Test CSRF Protection
 | ||
| [tabs]
 | ||
| ======
 | ||
| Java::
 | ||
| +
 | ||
| [source,java,role="primary"]
 | ||
| ----
 | ||
| import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.*;
 | ||
| import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.*;
 | ||
| import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
 | ||
| import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
 | ||
| 
 | ||
| @ExtendWith(SpringExtension.class)
 | ||
| @ContextConfiguration(classes = SecurityConfig.class)
 | ||
| @WebAppConfiguration
 | ||
| public class CsrfTests {
 | ||
| 
 | ||
| 	private MockMvc mockMvc;
 | ||
| 
 | ||
| 	@BeforeEach
 | ||
| 	public void setUp(WebApplicationContext applicationContext) {
 | ||
| 		this.mockMvc = MockMvcBuilders.webAppContextSetup(applicationContext)
 | ||
| 			.apply(springSecurity())
 | ||
| 			.build();
 | ||
| 	}
 | ||
| 
 | ||
| 	@Test
 | ||
| 	public void loginWhenValidCsrfTokenThenSuccess() throws Exception {
 | ||
| 		this.mockMvc.perform(post("/login").with(csrf())
 | ||
| 				.accept(MediaType.TEXT_HTML)
 | ||
| 				.param("username", "user")
 | ||
| 				.param("password", "password"))
 | ||
| 			.andExpect(status().is3xxRedirection())
 | ||
| 			.andExpect(header().string(HttpHeaders.LOCATION, "/"));
 | ||
| 	}
 | ||
| 
 | ||
| 	@Test
 | ||
| 	public void loginWhenInvalidCsrfTokenThenForbidden() throws Exception {
 | ||
| 		this.mockMvc.perform(post("/login").with(csrf().useInvalidToken())
 | ||
| 				.accept(MediaType.TEXT_HTML)
 | ||
| 				.param("username", "user")
 | ||
| 				.param("password", "password"))
 | ||
| 			.andExpect(status().isForbidden());
 | ||
| 	}
 | ||
| 
 | ||
| 	@Test
 | ||
| 	public void loginWhenMissingCsrfTokenThenForbidden() throws Exception {
 | ||
| 		this.mockMvc.perform(post("/login")
 | ||
| 				.accept(MediaType.TEXT_HTML)
 | ||
| 				.param("username", "user")
 | ||
| 				.param("password", "password"))
 | ||
| 			.andExpect(status().isForbidden());
 | ||
| 	}
 | ||
| 
 | ||
| 	@Test
 | ||
| 	@WithMockUser
 | ||
| 	public void logoutWhenValidCsrfTokenThenSuccess() throws Exception {
 | ||
| 		this.mockMvc.perform(post("/logout").with(csrf())
 | ||
| 				.accept(MediaType.TEXT_HTML))
 | ||
| 			.andExpect(status().is3xxRedirection())
 | ||
| 			.andExpect(header().string(HttpHeaders.LOCATION, "/login?logout"));
 | ||
| 	}
 | ||
| }
 | ||
| ----
 | ||
| 
 | ||
| Kotlin::
 | ||
| +
 | ||
| [source,kotlin,role="secondary"]
 | ||
| ----
 | ||
| import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.*
 | ||
| import org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.*
 | ||
| import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*
 | ||
| import org.springframework.test.web.servlet.result.MockMvcResultMatchers.*
 | ||
| 
 | ||
| @ExtendWith(SpringExtension::class)
 | ||
| @ContextConfiguration(classes = [SecurityConfig::class])
 | ||
| @WebAppConfiguration
 | ||
| class CsrfTests {
 | ||
| 	private lateinit var mockMvc: MockMvc
 | ||
| 
 | ||
| 	@BeforeEach
 | ||
| 	fun setUp(applicationContext: WebApplicationContext) {
 | ||
| 		mockMvc = MockMvcBuilders.webAppContextSetup(applicationContext)
 | ||
| 			.apply<DefaultMockMvcBuilder>(springSecurity())
 | ||
| 			.build()
 | ||
| 	}
 | ||
| 
 | ||
| 	@Test
 | ||
| 	fun loginWhenValidCsrfTokenThenSuccess() {
 | ||
| 		mockMvc.perform(post("/login").with(csrf())
 | ||
| 				.accept(MediaType.TEXT_HTML)
 | ||
| 				.param("username", "user")
 | ||
| 				.param("password", "password"))
 | ||
| 			.andExpect(status().is3xxRedirection)
 | ||
| 			.andExpect(header().string(HttpHeaders.LOCATION, "/"))
 | ||
| 	}
 | ||
| 
 | ||
| 	@Test
 | ||
| 	fun loginWhenInvalidCsrfTokenThenForbidden() {
 | ||
| 		mockMvc.perform(post("/login").with(csrf().useInvalidToken())
 | ||
| 				.accept(MediaType.TEXT_HTML)
 | ||
| 				.param("username", "user")
 | ||
| 				.param("password", "password"))
 | ||
| 			.andExpect(status().isForbidden)
 | ||
| 	}
 | ||
| 
 | ||
| 	@Test
 | ||
| 	fun loginWhenMissingCsrfTokenThenForbidden() {
 | ||
| 		mockMvc.perform(post("/login")
 | ||
| 				.accept(MediaType.TEXT_HTML)
 | ||
| 				.param("username", "user")
 | ||
| 				.param("password", "password"))
 | ||
| 			.andExpect(status().isForbidden)
 | ||
| 	}
 | ||
| 
 | ||
| 	@Test
 | ||
| 	@WithMockUser
 | ||
| 	@Throws(Exception::class)
 | ||
| 	fun logoutWhenValidCsrfTokenThenSuccess() {
 | ||
| 		mockMvc.perform(post("/logout").with(csrf())
 | ||
| 				.accept(MediaType.TEXT_HTML))
 | ||
| 			.andExpect(status().is3xxRedirection)
 | ||
| 			.andExpect(header().string(HttpHeaders.LOCATION, "/login?logout"))
 | ||
| 	}
 | ||
| }
 | ||
| ----
 | ||
| ======
 | ||
| 
 | ||
| [[disable-csrf]]
 | ||
| == Disable CSRF Protection
 | ||
| 
 | ||
| By default, CSRF protection is enabled, which affects <<csrf-integration,integrating with the backend>> and <<csrf-testing,testing>> your application.
 | ||
| Before disabling CSRF protection, consider whether it xref:features/exploits/csrf.adoc#csrf-when[makes sense for your application].
 | ||
| 
 | ||
| You can also consider whether only certain endpoints do not require CSRF protection and configure an ignoring rule, as in the following example:
 | ||
| 
 | ||
| [[disable-csrf-ignoring-configuration]]
 | ||
| .Ignoring Requests
 | ||
| [tabs]
 | ||
| ======
 | ||
| Java::
 | ||
| +
 | ||
| [source,java,role="primary"]
 | ||
| ----
 | ||
| @Configuration
 | ||
| @EnableWebSecurity
 | ||
| public class SecurityConfig {
 | ||
| 
 | ||
|     @Bean
 | ||
|     public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
 | ||
|         http
 | ||
|             // ...
 | ||
|             .csrf((csrf) -> csrf
 | ||
|                 .ignoringRequestMatchers("/api/*")
 | ||
|             );
 | ||
|         return http.build();
 | ||
|     }
 | ||
| }
 | ||
| ----
 | ||
| 
 | ||
| Kotlin::
 | ||
| +
 | ||
| [source,kotlin,role="secondary"]
 | ||
| ----
 | ||
| import org.springframework.security.config.annotation.web.invoke
 | ||
| 
 | ||
| @Configuration
 | ||
| @EnableWebSecurity
 | ||
| class SecurityConfig {
 | ||
| 
 | ||
|     @Bean
 | ||
|     open fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
 | ||
|         http {
 | ||
|             // ...
 | ||
|             csrf {
 | ||
|                 ignoringRequestMatchers("/api/*")
 | ||
|             }
 | ||
|         }
 | ||
|         return http.build()
 | ||
|     }
 | ||
| }
 | ||
| ----
 | ||
| 
 | ||
| XML::
 | ||
| +
 | ||
| [source,xml,role="secondary"]
 | ||
| ----
 | ||
| <http>
 | ||
| 	<!-- ... -->
 | ||
| 	<csrf request-matcher-ref="csrfMatcher"/>
 | ||
| </http>
 | ||
| <b:bean id="csrfMatcher"
 | ||
|     class="org.springframework.security.web.util.matcher.AndRequestMatcher">
 | ||
|     <b:constructor-arg value="#{T(org.springframework.security.web.csrf.CsrfFilter).DEFAULT_CSRF_MATCHER}"/>
 | ||
|     <b:constructor-arg>
 | ||
|         <b:bean class="org.springframework.security.web.util.matcher.NegatedRequestMatcher">
 | ||
|             <b:bean class="org.springframework.security.web.util.matcher.AntPathRequestMatcher">
 | ||
|                 <b:constructor-arg value="/api/*"/>
 | ||
|             </b:bean>
 | ||
|         </b:bean>
 | ||
|     </b:constructor-arg>
 | ||
| </b:bean>
 | ||
| ----
 | ||
| ======
 | ||
| 
 | ||
| If you need to disable CSRF protection, you can do so using the following configuration:
 | ||
| 
 | ||
| [[disable-csrf-configuration]]
 | ||
| .Disable CSRF
 | ||
| [tabs]
 | ||
| ======
 | ||
| Java::
 | ||
| +
 | ||
| [source,java,role="primary"]
 | ||
| ----
 | ||
| @Configuration
 | ||
| @EnableWebSecurity
 | ||
| public class SecurityConfig {
 | ||
| 
 | ||
| 	@Bean
 | ||
| 	public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
 | ||
| 		http
 | ||
| 			// ...
 | ||
| 			.csrf((csrf) -> csrf.disable());
 | ||
| 		return http.build();
 | ||
| 	}
 | ||
| }
 | ||
| ----
 | ||
| 
 | ||
| Kotlin::
 | ||
| +
 | ||
| [source,kotlin,role="secondary"]
 | ||
| ----
 | ||
| import org.springframework.security.config.annotation.web.invoke
 | ||
| 
 | ||
| @Configuration
 | ||
| @EnableWebSecurity
 | ||
| class SecurityConfig {
 | ||
| 
 | ||
|     @Bean
 | ||
|     open fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
 | ||
|         http {
 | ||
|             // ...
 | ||
|             csrf {
 | ||
|                 disable()
 | ||
|             }
 | ||
|         }
 | ||
|         return http.build()
 | ||
|     }
 | ||
| }
 | ||
| ----
 | ||
| 
 | ||
| XML::
 | ||
| +
 | ||
| [source,xml,role="secondary"]
 | ||
| ----
 | ||
| <http>
 | ||
| 	<!-- ... -->
 | ||
| 	<csrf disabled="true"/>
 | ||
| </http>
 | ||
| ----
 | ||
| ======
 | ||
| 
 | ||
| [[csrf-considerations]]
 | ||
| == CSRF Considerations
 | ||
| 
 | ||
| There are a few special considerations when implementing protection against CSRF attacks.
 | ||
| This section discusses those considerations as they pertain to servlet environments.
 | ||
| See xref:features/exploits/csrf.adoc#csrf-considerations[CSRF Considerations] for a more general discussion.
 | ||
| 
 | ||
| [[csrf-considerations-login]]
 | ||
| === Logging In
 | ||
| 
 | ||
| It is important to xref:features/exploits/csrf.adoc#csrf-considerations-login[require CSRF for log in] requests to protect against forging log in attempts.
 | ||
| Spring Security's servlet support does this out of the box.
 | ||
| 
 | ||
| [[csrf-considerations-logout]]
 | ||
| === Logging Out
 | ||
| 
 | ||
| It is important to xref:features/exploits/csrf.adoc#csrf-considerations-logout[require CSRF for log out] requests to protect against forging logout attempts.
 | ||
| If CSRF protection is enabled (the default), Spring Security's `LogoutFilter` will only process HTTP POST requests.
 | ||
| This ensures that logging out requires a CSRF token and that a malicious user cannot forcibly log your users out.
 | ||
| 
 | ||
| The easiest approach is to use a form to log the user out.
 | ||
| If you really want a link, you can use JavaScript to have the link perform a POST (maybe on a hidden form).
 | ||
| For browsers with JavaScript that is disabled, you can optionally have the link take the user to a log out confirmation page that performs the POST.
 | ||
| 
 | ||
| If you really want to use HTTP GET with logout, you can do so.
 | ||
| However, remember that this is generally not recommended.
 | ||
| For example, the following logs out when the `/logout` URL is requested with any HTTP method:
 | ||
| 
 | ||
| .Log Out with Any HTTP Method
 | ||
| [tabs]
 | ||
| ======
 | ||
| Java::
 | ||
| +
 | ||
| [source,java,role="primary"]
 | ||
| ----
 | ||
| @Configuration
 | ||
| @EnableWebSecurity
 | ||
| public class SecurityConfig {
 | ||
| 
 | ||
| 	@Bean
 | ||
| 	public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
 | ||
| 		http
 | ||
| 			// ...
 | ||
| 			.logout((logout) -> logout
 | ||
| 				.logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
 | ||
| 			);
 | ||
| 		return http.build();
 | ||
| 	}
 | ||
| }
 | ||
| ----
 | ||
| 
 | ||
| Kotlin::
 | ||
| +
 | ||
| [source,kotlin,role="secondary"]
 | ||
| ----
 | ||
| import org.springframework.security.config.annotation.web.invoke
 | ||
| 
 | ||
| @Configuration
 | ||
| @EnableWebSecurity
 | ||
| class SecurityConfig {
 | ||
| 
 | ||
|     @Bean
 | ||
|     open fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
 | ||
|         http {
 | ||
|             // ...
 | ||
|             logout {
 | ||
|                 logoutRequestMatcher = AntPathRequestMatcher("/logout")
 | ||
|             }
 | ||
|         }
 | ||
|         return http.build()
 | ||
|     }
 | ||
| }
 | ||
| ----
 | ||
| ======
 | ||
| 
 | ||
| See the xref:servlet/authentication/logout.adoc[Logout] chapter for more information.
 | ||
| 
 | ||
| [[considerations-csrf-timeouts]]
 | ||
| === CSRF and Session Timeouts
 | ||
| 
 | ||
| By default, Spring Security stores the CSRF token in the `HttpSession` using the <<csrf-token-repository-httpsession,`HttpSessionCsrfTokenRepository`>>.
 | ||
| This can lead to a situation where the session expires, leaving no CSRF token to validate against.
 | ||
| 
 | ||
| We have already discussed xref:features/exploits/csrf.adoc#csrf-considerations-timeouts[general solutions] to session timeouts.
 | ||
| This section discusses the specifics of CSRF timeouts as it pertains to the servlet support.
 | ||
| 
 | ||
| You can change the storage of the CSRF token to be in a cookie.
 | ||
| For details, see the <<csrf-token-repository-cookie>> section.
 | ||
| 
 | ||
| If a token does expire, you might want to customize how it is handled by specifying a <<csrf-access-denied-handler,custom `AccessDeniedHandler`>>.
 | ||
| The custom `AccessDeniedHandler` can process the `InvalidCsrfTokenException` any way you like.
 | ||
| 
 | ||
| [[csrf-considerations-multipart]]
 | ||
| === Multipart (file upload)
 | ||
| 
 | ||
| We have xref:features/exploits/csrf.adoc#csrf-considerations-multipart[already discussed] how protecting multipart requests (file uploads) from CSRF attacks causes a https://en.wikipedia.org/wiki/Chicken_or_the_egg[chicken and the egg] problem.
 | ||
| When JavaScript is available, we _recommend_ <<csrf-integration-javascript-other,including the CSRF token in an HTTP request header>> to side-step the issue.
 | ||
| 
 | ||
| If JavaScript is not available, the following sections discuss options for placing the CSRF token in the <<csrf-considerations-multipart-body,body>> and <<csrf-considerations-multipart-url,url>> within a servlet application.
 | ||
| 
 | ||
| [NOTE]
 | ||
| ====
 | ||
| You can find more information about using multipart forms with Spring in the https://docs.spring.io/spring-framework/docs/current/reference/html/web.html#mvc-multipart[Multipart Resolver] section of the Spring reference and the {spring-framework-api-url}org/springframework/web/multipart/support/MultipartFilter.html[`MultipartFilter` javadoc].
 | ||
| ====
 | ||
| 
 | ||
| [[csrf-considerations-multipart-body]]
 | ||
| ==== Place CSRF Token in the Body
 | ||
| 
 | ||
| We have xref:features/exploits/csrf.adoc#csrf-considerations-multipart-body[already discussed] the tradeoffs of placing the CSRF token in the body.
 | ||
| In this section, we discuss how to configure Spring Security to read the CSRF from the body.
 | ||
| 
 | ||
| To read the CSRF token from the body, the `MultipartFilter` is specified before the Spring Security filter.
 | ||
| Specifying the `MultipartFilter` before the Spring Security filter means that there is no authorization for invoking the `MultipartFilter`, which means anyone can place temporary files on your server.
 | ||
| However, only authorized users can submit a file that is processed by your application.
 | ||
| In general, this is the recommended approach because the temporary file upload should have a negligible impact on most servers.
 | ||
| 
 | ||
| .Configure `MultipartFilter`
 | ||
| [tabs]
 | ||
| ======
 | ||
| Java::
 | ||
| +
 | ||
| [source,java,role="primary"]
 | ||
| ----
 | ||
| public class SecurityApplicationInitializer extends AbstractSecurityWebApplicationInitializer {
 | ||
| 
 | ||
| 	@Override
 | ||
| 	protected void beforeSpringSecurityFilterChain(ServletContext servletContext) {
 | ||
| 		insertFilters(servletContext, new MultipartFilter());
 | ||
| 	}
 | ||
| }
 | ||
| ----
 | ||
| 
 | ||
| Kotlin::
 | ||
| +
 | ||
| [source,kotlin,role="secondary"]
 | ||
| ----
 | ||
| class SecurityApplicationInitializer : AbstractSecurityWebApplicationInitializer() {
 | ||
|     override fun beforeSpringSecurityFilterChain(servletContext: ServletContext?) {
 | ||
|         insertFilters(servletContext, MultipartFilter())
 | ||
|     }
 | ||
| }
 | ||
| ----
 | ||
| 
 | ||
| XML::
 | ||
| +
 | ||
| [source,xml,role="secondary"]
 | ||
| ----
 | ||
| <filter>
 | ||
| 	<filter-name>MultipartFilter</filter-name>
 | ||
| 	<filter-class>org.springframework.web.multipart.support.MultipartFilter</filter-class>
 | ||
| </filter>
 | ||
| <filter>
 | ||
| 	<filter-name>springSecurityFilterChain</filter-name>
 | ||
| 	<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
 | ||
| </filter>
 | ||
| <filter-mapping>
 | ||
| 	<filter-name>MultipartFilter</filter-name>
 | ||
| 	<url-pattern>/*</url-pattern>
 | ||
| </filter-mapping>
 | ||
| <filter-mapping>
 | ||
| 	<filter-name>springSecurityFilterChain</filter-name>
 | ||
| 	<url-pattern>/*</url-pattern>
 | ||
| </filter-mapping>
 | ||
| ----
 | ||
| ======
 | ||
| 
 | ||
| [NOTE]
 | ||
| ====
 | ||
| To ensure that `MultipartFilter` is specified before the Spring Security filter with XML configuration, you can ensure the `<filter-mapping>` element of the `MultipartFilter` is placed before the `springSecurityFilterChain` within the `web.xml` file.
 | ||
| ====
 | ||
| 
 | ||
| [[csrf-considerations-multipart-url]]
 | ||
| ==== Include a CSRF Token in a URL
 | ||
| 
 | ||
| If letting unauthorized users upload temporary files is not acceptable, an alternative is to place the `MultipartFilter` after the Spring Security filter and include the CSRF as a query parameter in the action attribute of the form.
 | ||
| Since the `CsrfToken` is exposed as an <<csrf-token-request-handler,`HttpServletRequest` attribute named `_csrf`>>, we can use that to create an `action` with the CSRF token in it.
 | ||
| The following example does this with a JSP:
 | ||
| 
 | ||
| .CSRF Token in Action
 | ||
| [source,html]
 | ||
| ----
 | ||
| <form method="post"
 | ||
| 	action="./upload?${_csrf.parameterName}=${_csrf.token}"
 | ||
| 	enctype="multipart/form-data">
 | ||
| ----
 | ||
| 
 | ||
| [[csrf-considerations-override-method]]
 | ||
| === HiddenHttpMethodFilter
 | ||
| 
 | ||
| We have xref:features/exploits/csrf.adoc#csrf-considerations-multipart-body[already discussed] the trade-offs of placing the CSRF token in the body.
 | ||
| 
 | ||
| In Spring's Servlet support, overriding the HTTP method is done by using {spring-framework-api-url}org/springframework/web/filter/reactive/HiddenHttpMethodFilter.html[`HiddenHttpMethodFilter`].
 | ||
| You can find more information in the https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#mvc-rest-method-conversion[HTTP Method Conversion] section of the reference documentation.
 | ||
| 
 | ||
| [[csrf-further-reading]]
 | ||
| == Further Reading
 | ||
| 
 | ||
| Now that you have reviewed CSRF protection, consider learning more about xref:servlet/exploits/index.adoc[exploit protection] including xref:servlet/exploits/headers.adoc[secure headers] and the xref:servlet/exploits/firewall.adoc[HTTP firewall] or move on to learning how to xref:servlet/test/index.adoc[test] your application.
 |