CSRF background and introduction

CSRF (Cross Site Request Forgery) is a network attack method, which was listed as one of the Top 20 Security risks on the Internet in 2007. Other security risks, such as SQL script injection and cross-site scripting attacks, have become well known in recent years, and many websites have taken precautions against them. However, CSRF is still a foreign concept to most people. Even Gmail, as well known, had a CSRF vulnerability at the end of 2007, which caused huge losses to Gmail users.

CSRF attack instance

A CSRF attack can fake requests on the victim’s behalf and send them to the target site without the victim’s knowledge to perform operations protected by permissions without authorization. Victims, for example, Bob has a deposit in the bank, through to the bank send requests to http://bank.example/withdraw? website Account =bob&amount=1000000&for= BOB2 Enables Bob to transfer 1000000 deposits to boB2. Typically, after the request is sent to the site, the server first verifies that the request came from a valid session and that the session’s user Bob has logged in successfully. Mallory himself had an account at the bank and knew that the URL could transfer money. Mallory can send a request to our bank: http://bank.example/withdraw? The account = bob&amount = 1000000 & for = Mallory. But the request comes from Mallory, not Bob, who cannot pass security authentication, so the request will not work. At this moment, Mallory thought of using CSRF attacks, he first make a web site and insert the following code in the web site: SRC = “http://bank.example/withdraw? Account = Bob&amount =1000000&for=Mallory “, and entice Bob to visit his website by advertising etc. When Bob visits the site, the above URL is sent from Bob’s browser to the bank, and the request is sent to the bank server with a cookie from Bob’s browser. In most cases, the request fails because it asks for Bob’s authentication information. However, if Bob happens to visit his bank shortly after that, his browser’s session with the bank’s web site has not expired, and the browser’s cookie contains Bob’s authentication information. The url request will be answered, and the money will be transferred from Bob’s account to Mallory’s, without Bob knowing it. When Bob later found that the money was missing, even if he checked the bank logs, he could only find that there was indeed a legitimate request from him to transfer the money, without any trace of attack. Mallory gets the money and gets away with it.

CSRF attack object

Before discussing how to defend against CSRF, it is important to know what CSRF attacks, that is, what you want to protect. As can be seen from the above examples, a CSRF attack means that the hacker uses the victim’s cookie to cheat the server into trust, but the hacker cannot get the cookie, nor can he see the content of the cookie. In addition, the result returned by the server cannot be parsed by the hacker due to the same origin policy of the browser. Therefore, the hacker gets nothing from the returned result, and all he can do is send a request to the server to execute the command described in the request, changing the value of the data directly on the server side, rather than stealing the data from the server. Therefore, we want to protect the services that can directly change the data, but for the services that read the data, CSRF protection is not required. For example, the transfer request in the banking system will directly change the amount of the account, which will be attacked by CSRF and need to be protected. However, the query balance is a reading operation of the amount, which does not change the data. CSRF attacks cannot parse the results returned by the server, so no protection is required.


Back to the first page

Current strategies to defend against CSRF

In the industry, there are three main defenses against CSRF attacks: verifying HTTP Referer fields; Add token to request address and verify; Customize and validate properties in HTTP headers. These three strategies are described in detail below.

Validate the HTTP Referer field

According to the HTTP protocol, there is a field in the HTTP header called Referer that records the source address of the HTTP request. Under normal circumstances, the limited access to a secure page requests from the same site, such as the need to visit http://bank.example/withdraw? Account = Bob&Amount =1000000&for=Mallory, the user must first log in to bank.Example and then trigger the transfer event by clicking the button on the page. In this case, the Referer value of the transfer request will be the URL of the page where the transfer button is located, usually starting with the bank.example domain name. If a hacker wants to carry out A CSRF attack on a bank’s website, he can only construct a request on his own website. When a user sends a request to the bank through the hacker’s website, the Referer of the request is directed to the hacker’s own website. Therefore, to defend against CSRF attacks, bank websites only need to verify the Referer value of each transfer request. If the domain name starts with bank.example, it indicates that the request is from the bank website itself and is legitimate. If the Referer is any other site, it could be a CSRF attack by a hacker to reject the request.

The obvious benefit of this approach is that it is so simple that the average developer of a site doesn’t have to worry about CSRF vulnerabilities, just adding a single interceptor to all security-sensitive requests at the end to check the Referer value. Especially for the current existing system, there is no need to change any existing code and logic of the current system, no risk, very convenient.

However, this approach is not foolproof. The value of the Referer is provided by the browser. Although there are clear requirements on the HTTP protocol, the specific implementation of the Referer by each browser may be different, and there is no guarantee that the browser itself is free of security vulnerabilities. The method of verifying the Referer value relies on the security of a third party (i.e. the browser), which in theory is not secure. In fact, for some browsers, such as IE6 or FF2, there are already ways to tamper with the Referer value. If the bank.example site supports Internet Explorer 6, the hacker could have set the Referer value of the user’s browser to an address that starts with the bank.example domain name, so that it can be verified and CSRF attacks can be carried out.

Even with the latest browsers, hackers can’t tamper with the Referer value, which is problematic. Because Referer records the source of the user’s access, some users feel that this will violate their privacy, especially some organizations concerned that the Referer value will leak some information from their internal network to the external network. Therefore, users themselves can set the browser to no longer provide Referer when sending requests. When they visit the bank’s website normally, the website will consider the request as a CSRF attack because it does not have the Referer value and deny the access to legitimate users.

Add token to request address and validate

The reason why CSRF attack can be successful is that the hacker can completely forge the user’s request, and all the user authentication information in the request is in the cookie, so the hacker can directly use the user’s own cookie to pass the security authentication without knowing the authentication information. The key to defending against CSRF is to put information in the request that a hacker cannot forge and that does not exist in a cookie. A randomly generated token can be added to the HTTP request as a parameter, and an interceptor can be established on the server side to verify the token. If there is no token in the request or the token content is incorrect, the request may be rejected as a CSRF attack.

This is more secure than checking the Referer. Tokens can be generated after the user logs in and placed in the session, and then taken out of the session on each request and compared with the tokens in the request. The difficulty with this approach, however, is how to add tokens to the request as parameters. For GET requests, the token is appended to the request address so that the URL becomes http://url? Csrftoken = tokenvalue. For POST requests, add <input type= “hidden” name= “csrFToken” value= “tokenValue” /> at the end of the form to add the token as a parameter to the request. However, in a website, there are so many places to accept requests that adding a token to each request is cumbersome and easy to miss. The usual method is to traverse the dom tree with javascript every time the page loads. Add the token after all a and FORM tags in the DOM. This solves most requests, but for HTML code that is generated dynamically after the page loads, this approach does not work and requires the programmer to manually add tokens at coding time.

Another disadvantage of this approach is that it is difficult to guarantee the security of tokens themselves. Especially in some forums and other websites that support users to publish their own content, hackers can publish their own personal website address. Since the system also adds a token to the address, the hacker can get the token on his own website and launch a CSRF attack right away. In order to avoid this, the system can add a judgment when adding the token, if the link is linked to their own site, add the token later, if it is to the Internet, do not add. However, even if the CSRFtoken is not attached to the request as a parameter, a hacker’s site can also obtain the token value via the Referer to launch a CSRF attack. This is why some users prefer to turn off the browser Referer manually.

Customize and validate properties in HTTP headers

This method also uses the token and validates it. Unlike the previous method, instead of placing the token in the HTTP request as a parameter, it places it in a custom attribute in the HTTP header. With the XMLHttpRequest class, you can add the CSRFToken HTTP header attribute and put the token value into all of the class requests at once. This eliminates the inconvenience of adding the token to the request in the previous method, and the XMLHttpRequest address is not logged in the browser’s address bar, and the token is not leaked to other sites through the Referer.

However, this approach has significant limitations. XMLHttpRequest is usually used for asynchronous partial page refresh in Ajax methods. Not all requests are suitable to be initiated with this class, and the page obtained through this class cannot be recorded by the browser, thus making it inconvenient for users to move forward, backward, refresh, and save. In addition, for legacy systems without CSRF protection, this approach to protection requires that all requests be converted to XMLHttpRequest requests, which is almost an entire web site rewrite, an unacceptable cost.


Back to the first page

Java code examples

The following sections illustrate each of the three methods in code, using Java as an example. Regardless of the method used, an interceptor on the server side is essential, which checks the incoming request for compliance and then decides whether to continue or discard the request based on the result. In Java, interceptors are implemented by filters. We can write a Filter and configure it in web.xml to intercept requests for access to all resources that need CSRF protection.

The Referer validation code for the request in the filter is as follows

Listing 1. Validate the Referer in the Filter
String Referer = request.getheader ("Referer"); If ((Referer! = null) && (referer. The trim (). The startsWith (" bank. Example "))) {chain. DoFilter (request, response); } else {request. GetRequestDispatcher (" error. JSP "). The forward (request, response); }Copy the code

The above code gets the Referer value, evaluates it, and if it is non-empty and starts with bank.example, continues the request, otherwise it could be a CSRF attack and go to the error.jsp page.

To further verify the token value in the request, the code is as follows

Listing 2. Validate the token in the request in filter
HttpServletRequest req = (HttpServletRequest)request; HttpSession s = req.getSession(); // Get the csrfToken attribute from session. String sToken = (String) s.get_attribute (" csrftoken "); If (sToken == null){// Generate a new token into the session sToken = generateToken(); S.s etAttribute (" csrftoken, "sToken); chain.doFilter(request, response); } else{// Get csrfToken from HTTP header String xhrToken = req.getheader (" csrftoken "); PToken = req.getParameter(" csrfToken "); if(sToken ! = null && xhrToken ! = null && sToken.equals(xhrToken)){ chain.doFilter(request, response); }else if(sToken ! = null && pToken ! = null && sToken.equals(pToken)){ chain.doFilter(request, response); } else {request. GetRequestDispatcher (" error. JSP "). The forward (request, response); }}Copy the code

First, check whether there is a CSRftoken in the session. If there is no cSRFtoken in the session, it is considered as the first access and the session is newly established. In this case, a new token is generated, placed in the session, and the request continues to be executed. If there is a cSRFToken in the session, then the user has established an active session with the server. If there is a cSRFToken in the session, then the user has established an active session with the server. We try to get the CSRFToken parameter from the request and the cSRFToken custom attribute from the HTTP header respectively and compare it with the value in the session. As long as there is a valid token in one place, the request is judged to be valid and can continue to execute, otherwise we will go to the error page. There are many ways to generate tokens, and any random algorithm can be used. Java’s UUID class is also a good choice.

In addition to using filter to verify the token value on the server side, we also need to append the token to each request on the client side, which uses JS to append cSRFToken code to the link and form request address in HTML, where token has been defined as a global variable. The value can be obtained from session.

Listing 3. Attach tokens to requests on the client side
function appendToken(){ updateForms(); updateTags(); } function updateForms () {/ / in the page, all the form elements of var forms = document. The getElementsByTagName (' form '); for(i=0; i<forms.length; i++) { var url = forms[i].action; / / if the form of action value is empty, are not additional csrftoken if (url = = null | | url = = "") continue; Var e = document.createElement("input"); var e = document.createElement("input"); e.name = "csrftoken"; e.value = token; e.type="hidden"; forms[i].appendChild(e); } } function updateTags() { var all = document.getElementsByTagName('a'); var len = all.length; For (var I =0; i<len; i++) { var e = all[i]; updateTag(e, 'href', token); } } function updateTag(element, attr, token) { var location = element.getAttribute(attr); if(location ! = null && location ! = '' '' ) { var fragmentIndex = location.indexOf('#'); var fragment = null; if(fragmentIndex ! Fragment = location. subString (fragmentIndex); // Fragment = location.substring(fragmentIndex); location = location.substring(0,fragmentIndex); } var index = location.indexOf('? '); if(index ! Location = location + '&csrftoken=' + token; } else {// location = location + '? csrftoken=' + token; } if(fragment ! = null){ location += fragment; } element.setAttribute(attr, location); }}Copy the code

In the client HTML, there are two main places to add tokens, one is the form and the other is the link A. This code first iterates through all the forms and adds a hidden field at the end of the form to put the CSRFToken into it. The code then iterates through all the link tag A, adding the cSRFToken argument to its href attribute. Note that in the case of A.ref, the attribute may already have parameters, or an anchor tag. Therefore, it is necessary to discuss the case by case and add cSRFToken in different formats.

If your site uses XMLHttpRequest, you also need to customize the cSRFToken attribute in the HTTP header. Using dojo. XHR, add the following code to the XMLHttpRequest custom attribute:

Listing 4. Custom attributes in the HTTP header
var plainXhr = dojo.xhr; . / / rewrite the dojo XHR method dojo XHR = function (method, args, hasBody) {/ / make sure the header object exists the args. The headers = args. The header | | {}; tokenValue = '<%=request.getSession(false).getAttribute("csrftoken")%>'; var token = dojo.getObject("tokenValue"); Args. headers["csrftoken"] = (token)? token : " "; return plainXhr(method,args,hasBody); };Copy the code

This overwrites the dojo. XHR method by first ensuring that dojo. XHR has HTTP headers, then adding the CSRFToken field to args.headers and taking the token value out of the session and putting it in the field.


Back to the first page

CSRF defense method selection

As can be seen from the above discussion, there are some restraint methods to deal with CSRF attacks in the industry at present, but each method has advantages and disadvantages, and none of them is perfect. How to choose the right method is very important. If the site is an existing system and wants to obtain a certain degree of CSRF protection in the shortest time, then verifying the Referer method is the most convenient. In order to increase security, you can choose not to support the lower version of the browser, after all, for the moment, The Referer value of older browsers like IE7+ and FF3+ cannot be tampered with.

If the system must support IE6, you still need high security. In most cases, XmlHttpRequest is not appropriate. Tokens can only be used as parameters in requests. If your system does not support users Posting information themselves, then this level of protection is sufficient. It’s still hard to prevent your tokens from being stolen and attacked by hackers. In this case, you need to carefully plan the various services provided by your website, identify the parts that allow users to publish their own information, separate them from other services, and use different tokens to protect them, so that you can effectively prevent hackers from attacking your key services and minimize the harm. After all, deleting a post from someone else’s account is less serious than simply transferring a large sum of money from someone else’s account.

If you are developing an entirely new system, the options for resisting CSRF are much greater. I recommend that you use XMLHttpRequest to access important services as much as possible, which makes it much easier to add tokens. Also try to avoid using complex logic in JS code to construct regular synchronous requests to access CSRF protected resources such as window.location and document.createElement(” a “). This can also reduce unnecessary hassle when attaching tokens.

Finally, keep in mind that CSRF is not the only means of attack for hackers. No matter how well protected you are against CSRF, if you have other security vulnerabilities, such as cross-site scripting against XSS, then hackers can bypass your security and carry out various attacks, including CSRF, and your defenses will be useless.


Back to the first page

Summary and Prospect

It can be seen that CSRF is a very harmful attack and difficult to defend against. Although several defense strategies can resist CSRF attack to a large extent, there is no perfect solution. Some new approaches are being explored, such as using a different dynamic password for each request, combining Referer and token schemes, and even trying to modify the HTTP specification, but they are still immature and will take time to become fully operational and widely accepted by the industry. Before this, we must pay full attention to CSRF and choose the most appropriate strategy according to the actual situation of the system, so as to minimize the harm of CSRF.

The resources

learning

  • Wikipedia CSRF, here is a more comprehensive introduction to CSRF. En.wikipedia.org/wiki/Cross-…
  • CSRFGuard, an open source project, describes how to defend against CSRF by adding tokens to HTTP requests and verifying them. www.owasp.org/index.php/C…
  • Prevent cross-site Request Forgery: PCRF. Suggests a way to use tokens in PHP to defend against CSRF. Userweb.cs.utexas.edu/~samuel/PCR…
  • Robust confident for cross-site Request Forgery: analyzed some commonly used CSRF resistance methods and creatively proposed browser enhancement solutions.
  • DeveloperWorks Web Development Zone: Expand your Web development skills with articles and tutorials dedicated to Web technologies.
  • DeveloperWorks Ajax Resource Center: This is a one-stop center for information on the Ajax programming model, including numerous documents, tutorials, forums, blogs, wikis, and news. Any new Ajax information can be found here.
  • DeveloperWorks Web 2.0 Resource Center, a one-stop center for Web 2.0-related information, includes a wealth of Web 2.0 technical articles, tutorials, downloads, and related technical resources. You can also quickly learn about Web 2.0 concepts through the Getting Started Web 2.0 section.
  • Check out HTML5 Topics for more information and trends related to HTML5.

Did this article help you? Welcome to join the front End learning Group wechat group: