spring-security (24) CSRF

1. What is a CSRF attack?
Let 's take a specific example to illustrate this common attack mode
. 1.1 Suppose a bank's website provides the function of allowing the currently logged-in user to transfer money to other accounts. The format of the transfer request is as follows
POST /transfer HTTP/1.1
Host: bank.example.com
Cookie: JSESSIONID=randomid; Domain=bank.example.com; Secure; HttpOnly
Content-Type: application/x-www-form-urlencoded
amount=100.00&routingNumber=1234&account=9876

1.2 Now a user logs in to the bank's website and authenticates, and visits a malicious website without logging out. The malicious website contains the following html code segment
<form action="https://bank.example.com/transfer" method="post">
   <input type="hidden"name="amount" value="100.00"/>
   <input type="hidden"name="routingNumber" value="evilsRoutingNumber"/>
   <input type="hidden" name="account" value="evilsAccountNumber"/>
   <input type="submit" value="receive prize"/>
</form>

At this time, if the user clicks the [Receive Prize] button, you will transfer 100 yuan to the malicious attacker's account. This is because although the malicious website cannot obtain the user's cookie information, when the [Receive Prize] button is clicked to access the bank website , the cookie information will still be sent together. To make matters worse, with the help of javascript, the above process can be executed automatically, without waiting for the user to click the [receive prize] button, as long as you open this page, your money will be stolen, which is also our common phishing website way of doing.

Like this, although the user is visiting another website, this website pretends to be the current authenticated user to visit the website the user is visiting to achieve an attack called CSRF.

2. Synchronous token mode
2.1 As can be seen from the above example, whether the transfer request is sent from the bank's own website or from a malicious website, the content is the same for the bank's server, so purely from the server We can't filter out those malicious requests. If we can take a measure to allow the bank's normal page to send a request to the server to provide a certificate, and this certificate cannot be provided by a malicious website, then the server side can reject those illegal requests very easily.
Synchronous token is such a method, which requires that when the client initiates a request, in addition to the cookie information, a random token value needs to be provided as a parameter. When the server receives a request, it will first parse the token value, then compare it with the expected value, and refuse to provide the service if it does not match.
2.2 In actual projects, we can relax the above rules and only require those requests that modify information to provide the token value, because according to the same-origin policy, those malicious websites cannot obtain the response results of our normal requests. After appending the token, our request example is as follows:
POST /transfer HTTP/1.1
Host: bank.example.com
Cookie: JSESSIONID=randomid; Domain=bank.example.com; Secure; HttpOnly
Content-Type: application/x-www-form-urlencoded
amount=100.00&routingNumber=1234&account=9876&_csrf=<secure-random>

In this way, since malicious websites cannot provide random values ​​corresponding to _csrf, forged requests will not be accepted by the server.
3. How to use spring security to prevent csrf attacks
3.1 Use correct http verbs
verb effect analogy to database operations
GET Get information from the server select
POST Create a new resource on the server insert
PUT Update a resource on the server, this request contains complete information update
PATCH Update a resource on the server with partial information update
DELETE delete a resource on the server delete
HEAD Ask the server for a response consistent with the GET request, but only with header information, and the response body will not be returned.   without
TRACE Echo the request received by the server, mainly for testing or diagnostics   without
OPTIONS Returns the HTTP request methods supported by the server for a specific resource   without

Make sure that the verb of the request to modify the information must be one of post, put, patch, delete.
3.2 Configuring CSRF
For spring security 4.0+, whether it is in the form of xml configuration or Java config, csrf is enabled by default, and can be closed in the following ways
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
  @Override
  protected void configure(HttpSecurity http) throws Exception {
  http
   .csrf().disable();
  }
}

By default, if the csrf check fails, spring security will return a 403 code to the client. You can customize the AccessDeniedHandler through the CsrfConfigurer class returned by the http.csrf() method to implement your own logic.
3.3 The interface contains CSRF-related settings.
We need to ensure that the CSRF token value is included in all requests to execute post, put, patch, and delete. The most direct way is to make the jstl expression obtain the value corresponding to _csrf from the request, as follows
<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>

In addition, spring also provides us with two convenient jsptags. For specific examples, refer to csrf jsptag.
In addition, if we use the thymeleaf template engine, the corresponding csrf attribute will be automatically added to the form form.
For specific examples, refer to [url url=https://github.com/fengyilin/spring-security-sample/tree/master/security-samples-javaconfig-csrf-thymeleaf]csrf-thymeleaf[/url]
3.4 CookieCsrfTokenRepository
in some occasions Next, we may need to store the csrf token value in the cookie. In this case, we can use CookieCsrfTokenRepository to achieve this function. By default, the key written to the cookie is XSRF-TOKEN, and the X-TOKEN of the request header is read from the request header. Read in XSRF-TOKEN or _csrf of parameter. It can be configured with the following code snippet
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
	@Override
	protected void configure(HttpSecurity http) throws Exception {
	http
   		.csrf()
    	.csrfTokenRepository(new CookieCsrfTokenRepository());
	}
}

By default, the information set in the cookie cannot be read by js. If js access is required, it needs to be set explicitly
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
	@Override
	protected void configure(HttpSecurity http) throws Exception {
		http
  		 .csrf()
   		 .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse());
	}
}

4 Some notes on using csrf
4.1 Timeouts
By default, the csrf token is stored in the httpsession. When the session expires, the AccessDeniedHandler will receive an InvalidCsrfTokenException. If we use the default AccessDeniedHandler of spring security, the client will receive a simple 403 error (because CSRF_FILTER is behind the authentication filter), we can deal with this problem in the following ways
  • Add js to the page, notify the user when the session is about to expire, and refresh the session by clicking the button
  • Customize AccessDeniedHandle and handle InvalidCsrfTokenException yourself
  • You can also store the csrf token in the CsrfTokenRepository (such as CookieCsrfTokenRepository), so that there will be no expiration problem, although there are security risks in storing the token, but in most cases there will be no problem

4.2 Login Problems
If csrf token protection is also enabled on the login page, HttpSession needs to be created when CsrfToken is generated before login. At this time, it is necessary to consider that if the user stays on the login page for a long time, it will cause the problem of session expiration, and directly return 403 when logging in (No permission to log in--), the current general solution is to use JavaScript to obtain the token value when clicking login, and then submit the login request, so that the session is only created when logging in, and the user can stay in the login interface for any time. , we can easily implement such a function using CsrfTokenArgumentResolver
@RestController
public class CsrfController {
 	@RequestMapping("/csrf")
	public CsrfToken csrf(CsrfToken token) {
	return token;
	}
}

At this point, it should be noted that the cors function cannot be applied to this endpoint for security.
4.3 Logout
By default, after the csrf token is enabled, the LogoutFilter only receives Post requests, and the csrf token value needs to be provided when logging out
@SuppressWarnings("unchecked")
private RequestMatcher getLogoutRequestMatcher(H http) {
	if (logoutRequestMatcher != null) {
		return logoutRequestMatcher;
	}
	if (http.getConfigurer(CsrfConfigurer.class) != null) {
		this.logoutRequestMatcher = new AntPathRequestMatcher(this.logoutUrl, "POST");
	}
	else {
		this.logoutRequestMatcher = new OrRequestMatcher(
			new AntPathRequestMatcher(this.logoutUrl, "GET"),
			new AntPathRequestMatcher(this.logoutUrl, "POST"),
			new AntPathRequestMatcher(this.logoutUrl, "PUT"),
			new AntPathRequestMatcher(this.logoutUrl, "DELETE")
		);
	}
	return this.logoutRequestMatcher;
}

If the security of the Logout operation is not so high, and the implementation does not want to be so complicated, it can be configured through the following code segment
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
	@Override
	protected void configure(HttpSecurity http) throws Exception {
	 http
		.logout()
		.logoutRequestMatcher(new AntPathRequestMatcher("/logout"));
	}
}

At this time, you can use any HTTP method to perform the logout operation.
4.4 File upload
can be solved in the following two ways
  • Put MultipartFilter in front of spring security related filters
  • public class SecurityApplicationInitializer extends AbstractSecurityWebApplicationInitializer {
    	@Override
    	protected void beforeSpringSecurityFilterChain(ServletContext servletContext) {
    	insertFilters(servletContext, new MultipartFilter());
    	}
    }
  • Append the token value to the action corresponding to the uploaded file
  •    <form action="./upload?${_csrf.parameterName}=${_csrf.token}" method="post" enctype="multipart/form- data">
       

    Guess you like

    Origin http://43.154.161.224:23101/article/api/json?id=326065584&siteId=291194637