Introduction to CSRF
CSRF (Cross-site request forgery), Chinese name: cross-site request forgery, also known as: one click attack/session riding, abbreviation: CSRF/XSRF.
For specific introductions and attack methods of SCRF, please refer to the introduction of Baidu Encyclopedia and the analysis of a big guy:
CSRF Baidu Encyclopedia briefly discusses CSRF attack methods
Configuration steps
1. Depend on jar package
<properties> <spring.security.version>4.2.2.RELEASE</spring.security.version> </properties> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-core</artifactId> <version>${spring.security.version}</version> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-web</artifactId> <version>${spring.security.version}</version> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-config</artifactId> <version>${spring.security.version}</version> </dependency> 2.web.xml configuration
<filter> <filter-name>springSecurityFilterChain</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> </filter> <filter-mapping> <filter-name>springSecurityFilterChain</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
3. Spring configuration file configuration
<bean id="csrfSecurityRequestMatcher"></bean> <security:http auto-config="true" use-expressions="true"> <security:headers> <security:frame-options disabled="true"/> </security:headers> <security:csrf request-matcher-ref="csrfSecurityRequestMatcher" /> </security:http>
4. Customize the implementation class of RequestMatcher CsrfSecurityRequestMatcher
This class is used to customize which requests do not require interception and filtering. If csrf is configured, all http requests are intercepted by CsrfFilter, and there is a private class DefaultRequiresCsrfMatcher in CsrfFilter.
Source code 1: DefaultRequiresCsrfMatcher class
private static final class DefaultRequiresCsrfMatcher implements RequestMatcher { private final HashSet<String> allowedMethods; private DefaultRequiresCsrfMatcher() { this.allowedMethods = new HashSet(Arrays.asList(new String[]{"GET", "HEAD", "TRACE", "OPTIONS"})); } public boolean matches(HttpServletRequest request) { return !this.allowedMethods.contains(request.getMethod()); } } From this source code, we can find that the POST method is excluded, that is, only the four types of methods such as GET|HEAD|TRACE|OPTIONS will be released. The http requests of other methods must verify whether the _csrf token is correct. Usually, when calling the rest interface service in the post method, there is no _csrf token, which will cause our rest interface to fail. We need to customize a class to release the interface of this type. Let’s take a look at our customized filters:
Source code 2: csrfSecurityRequestMatcher class
public class CsrfSecurityRequestMatcher implements RequestMatcher { private Pattern allowedMethods = Pattern.compile("^(GET|HEAD|TRACE|OPTIONS)$"); private RegexRequestMatcher unprotectedMatcher = new RegexRequestMatcher("^/rest/.*", null); @Override public boolean matches(HttpServletRequest request) { if(allowedMethods.matcher(request.getMethod()).matches()){ return false; } return !unprotectedMatcher.matches(request); } } Note: Generally, the rest interface services we define are all with /rest/, so if your project is not used, or there is no rest service in the project, this class can be completely omitted.
5.Post request configuration
Generally, there is a common jsp file in our project, which is referenced by each page, so we can make the following configuration in the common file:
<meta name="_csrf" content="${_csrf.token}"/> <meta name="_csrf_header" content="${_csrf.headerName}"/> <script> var token = $("meta[name='_csrf']").attr("content"); var header = $("meta[name='_csrf_header']").attr("content"); $.ajaxSetup({ beforeSend: function (xhr) { if(header && token ){ xhr.setRequestHeader(header, token); } }} ); </script> $.ajaxSetup means adding this header and token to all our requests, or put it in the form form. Note that _csrf should match the configuration in the configuration file of spring security, and the default is _csrf.
Source code analysis
We know that since csrf is configured, all http requests will be intercepted by CsrfFilter, so after looking at the source code of CsrfFilter, you will be clear about the principle at a glance. Here we only look at the specific filtering method:
Source code 3: doFilterInternal method of CsrfFilter
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { request.setAttribute(HttpServletResponse.class.getName(), response); CsrfToken csrfToken = this.tokenRepository.loadToken(request); boolean missingToken = csrfToken == null; if(missingToken) {//If the token is empty, it means that the first time you access it, generate a token object csrfToken = this.tokenRepository.generateToken(request); this.tokenRepository.saveToken(csrfToken, request, response); } request.setAttribute(CsrfToken.class.getName(), csrfToken); //Put the token object into the request, note that the key here is csrfToken.getParameterName()= _csrf, so we write it to death on the page. request.setAttribute(csrfToken.getParameterName(), csrfToken); //This machine is the filter we customize in the Spring configuration file, that is, GET, HEAD, TRACE, OPTIONS and our rest do not handle if(!this.requireCsrfProtectionMatcher.matches(request)) { filterChain.doFilter(request, response); } else { String actualToken = request.getHeader(csrfToken.getHeaderName()); if(actualToken == null) { actualToken = request.getParameter(csrfToken.getParameterName()); } if(!csrfToken.getToken().equals(actualToken)) { if(this.logger.isDebugEnabled()) { this.logger.debug("Invalid CSRF token found for " + UrlUtils.buildFullRequestUrl(request)); } if(missingToken) { this.accessDeniedHandler.handle(request, response, new MissingCsrfTokenException(actualToken)); } else { this.accessDeniedHandler.handle(request, response, new InvalidCsrfTokenException(csrfToken, actualToken)); } } else { filterChain.doFilter(request, response); } } }As can be seen from the source code, post requests other than our customized filters require token verification.
Originally, I wanted to take a screenshot to get a case, and then use the breakpoint to see the value transmission status of the page and the background... However, I can't upload pictures here and go crazy. OK, so much to summarize! If you have any wrong writing or have other questions, you can leave a message to communicate.
The above is all the content of this article. I hope it will be helpful to everyone's learning and I hope everyone will support Wulin.com more.