CSRF (Cross site request forgery) is a network attack that can be sent to a compromised site without the victim's knowledge of the victim's name forgery request, thereby performing a rights-protected operation with no authorization. There is a lot of harm. However, this attack mode is not well known, many websites have CSRF security loopholes. This paper first introduces the basic principle of CSRF and its harmfulness, then analyzes several defensive methods which are commonly used at present, and compares their merits and demerits. Finally, this article will show you how to defend against CSRF attacks in the Web site and share some best practices in the development process.
CSRF Background and introduction
CSRF (Cross site request forgery) is a network attack mode, which was listed as one of the 20 major security risks in the Internet in 2007. Other security risks, such as SQL script injection, cross-site scripting attacks, have been gradually known in recent years, and many websites have defended them. However, for most people, CSRF is still a strange concept. Even the well-known Gmail, at the end of 2007, there are CSRF loopholes, so that hackers to attack the users of Gmail caused huge losses.
CSRF Attack instances
The CSRF attack can be sent to the compromised site in the name of the victim without the knowledge of the victim, thereby performing an operation under rights protection if not authorized. For example, the victim Bob has a deposit at the bank, and by sending a request to the bank's website Http://bank.example/withdraw?account=bob&amount=1000000&for=bob2 can make Bob 1000000 of the deposit is transferred to BOB2 's account. Typically, after the request is sent to the Web site, the server verifies that the request is from a valid session and that the user Bob of the session has successfully logged in. The hacker Mallory himself has an account with the bank and knows that the URL above can transfer money. Mallory can send a request to the bank by itself: Http://bank.example/withdraw?account=bob&amount=1000000&for=Mallory. But this request comes from Mallory, not Bob, who cannot pass security authentication, so the request will not work. At this time, Mallory think of using CSRF attack way, he first make a website, put the following code in the site: src= "http://bank.example/withdraw?account=bob&amount=1000000 &for=mallory "and lured Bob to visit his website by advertising. When Bob visits the site, the above URLs are sent from Bob's browser to the bank, which is sent to the bank server with a cookie from Bob's browser. In most cases, the request fails because he requires BOB's authentication information. However, if Bob had just visited his bank shortly after, the session between his browser and the bank's website had not expired, and the browser's cookie contained Bob's authentication information. At this point, the tragedy occurred, the URL request will be answered, the money will be transferred from Bob's account to Mallory's account, and Bob was not informed. After Bob found that the account was less money, even if he went to the bank to check the log, he can only find that there is a legitimate request from his own transfer of funds, without any traces of attack. And Mallory can get the money and go unpunished.
CSRF object of attack
Before discussing how to defend against CSRF, it is very clear that the object of the CSRF attack is the object to be protected. From the above example, the CSRF attack is a hacker's use of the victim's cookie to defraud the server of trust, but hackers do not have access to cookies, but also do not see the content of cookies. In addition, for the results returned by the server, due to browser-origin policy restrictions, hackers can not be resolved. Therefore, the hacker cannot get anything from the returned results, all he can do is send a request to the server to execute the command described in the request, directly change the value of the data on the server side, rather than stealing the data from the server. Therefore, the objects we want to protect are those that can directly generate data changes, and for the services that read the data, there is no need for CSRF protection. For example, the transfer request in the banking system will change the amount of the account directly, will be CSRF attack, need to protect. The query balance is a read operation on the amount, does not change the data, the CSRF attack cannot resolve the results returned by the server, without protection.
Several strategies of current defensive CSRF
There are three main strategies for defending against CSRF attacks in the industry: Validating HTTP Referer fields, adding tokens to the request address and validating it, customizing properties in the HTTP header, and validating. These three strategies are described in detail below.
Validating HTTP Referer Fields
According to the HTTP protocol, there is a field in the HTTP header called Referer, which records the source address of the HTTP request. In general, requests to access a secure restricted page come from the same site, such as the need to access 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 on the button on the page. At this point, the Referer value of the transfer request will be the URL of the page where the transfer button is located, usually the address beginning with the Bank.example domain name. And if the hacker wants to carry on the CSRF attack to the bank website, he only constructs the request in his own website, when the user sends the request to the bank through the hacker's website, the request Referer is pointing at the hacker own website. Therefore, to defend against CSRF attacks, the bank website only needs to verify its Referer value for each transfer request, if it is a domain name beginning with bank.example, it is legitimate that the request is from the bank website itself. If Referer is a different Web site, it could be a hacker's CSRF attack, rejecting the request.
The obvious benefit of this approach is simplicity, the site's general developers do not need to worry about CSRF's vulnerability, only need to be in the end to all security-sensitive requests unified add an interceptor to check the value of Referer. Especially for current systems, 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, but each browser may have a different implementation for Referer, and there is no guarantee that the browser itself does not have a security vulnerability. The method of validating Referer values is to ensure that security is dependent on a third party (ie, the browser), which in theory is not secure. In fact, for some browsers, such as IE6 or FF2, there are ways to tamper with Referer values. If the Bank.example website supports IE6 browser, the hacker can completely set the Referer value of the user's browser to the address beginning with the Bank.example domain name, so that it can be authenticated for CSRF attacks.
Even with the latest browser, the hacker cannot tamper with the Referer value, and this method still has a problem. Because the Referer value records the user's access to the source, some users believe that this violates their own privacy, especially some organizations worry that the Referer value will disclose some information in the organization intranet to the external network. As a result, users can set their own browser to no longer provide Referer when sending requests. When they visit the bank website normally, the website will be considered as a CSRF attack because the request does not have Referer value, and deny access to legitimate users.
Add tokens to the request address and verify
CSRF attack was successful because the hacker could completely forge the user's request, and all the user authentication information in the request was in the cookie. So hackers can use the user's own cookie to pass security verification without knowing the authentication information. The key to defending against CSRF is to put in the request information that the hacker cannot forge, and that the information does not exist in the cookie. A randomly generated token can be added as a parameter in an HTTP request, and an interceptor is established on the server side to verify the token, and if no token or token content is incorrect in the request, it may be rejected as a CSRF attack.
This method is safer than checking the Referer, token can be generated after the user logs in and placed in the session, and then on each request to the token from the session, and the request in the Token for comparison, but the difficulty with this method is how to add tokens as parameters to the request. For a GET request, token is appended to the request address so that the URL becomes http://url?csrftoken=tokenvalue. For a POST request, add the <input type= "hidden" name= "Csrftoken" to the end of the form and value= "Tokenvalue", so that token is added to the request in the form of a parameter. However, in a Web site, there are many places to accept requests, it is cumbersome to add tokens to each request, and it is easy to miss out, usually using JavaScript to traverse the entire DOM tree every time the page loads, for all the A and form tags in the DOM Add token. This solves most of the requests, but this method has no effect on the dynamically generated HTML code after the page is loaded, and requires the programmer to add tokens manually when encoding.
One drawback of this approach is that it is difficult to secure the token itself. In particular, in some forums and other sites that support users to publish their own content, hackers can post their own personal website address. Since the system will also add tokens to this address, hackers can get this token on their website and can launch CSRF attacks immediately. In order to avoid this, the system can add tokens when adding a judgment, if the link is linked to their own site, in the back to add tokens, if it is to the outside network is not added. However, even if the csrftoken is not appended to the request in the form of a parameter, the hacker's website can also be Referer to get the token value to launch the CSRF attack. This is also why some users prefer to manually turn off the browser Referer feature.
Customize the properties in the HTTP header and verify
This approach is also using token and validating, unlike the previous method, where token is not placed in an HTTP request in the form of an argument, but instead placed in a custom attribute in the HTTP header. By XMLHttpRequest This class, you can add Csrftoken this HTTP header attribute to all requests at once, and put the token value into it. This solves the inconvenience of adding tokens to the request, while the address requested by XMLHttpRequest is not recorded in the browser's address bar, nor does it worry that tokens will be leaked to other websites through Referer.
However, the limitations of this approach are very large. XMLHttpRequest requests are usually used in the Ajax method for the partial page of the asynchronous refresh, not all requests are suitable for this class to initiate, and through the request of this kind of page can not be recorded by the browser, so as to advance, backward, refresh, collection and other operations, to the user inconvenience. In addition, for legacy systems that do not have CSRF protection, it is not acceptable to use this approach for protection, to change all requests to xmlhttprequest requests, almost to rewrite the entire site.
Java code Example
In Java as an example, the above three methods are shown separately in code. Regardless of the method used, the server-side interceptor is essential, and it is responsible for checking that incoming requests meet the requirements, and then depending on the results to decide whether to continue the request or discard. In Java, interceptors are implemented by filter. We can write a Filter and configure it in Web. XML to intercept requests that access all resources that require CSRF protection.
The Referer validation code for the request in the filter is as follows
Listing 1. Verifying the Referer in Filter
Gets the Referer value from the HTTP header String referer=request.getheader ("Referer"); Determines whether Referer starts with Bank.example if ((referer!=null) && (Referer.trim (). StartsWith ("Bank.example"))) { Chain.dofilter (request, response); } else{ request.getrequestdispatcher ("error.jsp"). Forward (request,response); }
The above code first obtains the Referer value, then makes the judgment, when its non-empty and starts with the bank.example, then continues the request, otherwise may be the CSRF attack, goes to the error.jsp page.
If you want to further verify the token value in the request, the code is as follows
Listing 2. Validating tokens in a request in filter
HttpServletRequest Req = (httpservletrequest) request; HttpSession s = req.getsession (); Get the Csrftoken property from the session String Stoken = (string) s.getattribute ("Csrftoken"); if (Stoken = = null) {//Generate a new token into the session Stoken = Generatetoken (); S.setattribute ("Csrftoken", Stoken); Chain.dofilter (request, response); } else{//Get csrftoken String Xhrtoken = Req.getheader ("Csrftoken") from the HTTP header; Get csrftoken String PToken = Req.getparameter ("Csrftoken") from the request parameter; if (Stoken! = NULL && Xhrtoken! = null && stoken.equals (Xhrtoken)) {chain.dofilter (Request, respons e); }else if (Stoken! = NULL && PToken! = null && stoken.equals (PToken)) {chain.dofilter (Request, RESPO NSE); }else{request.getrequestdispatcher ("error.jsp"). Forward (Request,response); } }
First judge there is no Csrftoken in the session, if not, it is considered the first visit, the session is a new establishment, then generate a new token, placed in the session, and continue to execute the request. If Csrftoken is already in session, then the user has established an active session with the server, which is to see if the token is included in the request, as the request may come from a regular access or XMLHttpRequest asynchronous access , we try to get the Csrftoken parameter from the request separately and get the Csrftoken custom attribute from the HTTP header and compare it with the value in the session, as long as there is a valid token in place, the decision request is valid, you can continue execution, or go to the error page. There are many ways to generate tokens, and any random algorithm can be used, and the Java UUID class is a good choice.
In addition to using filter on the server side to verify the token value, we also need to attach this token to each request on the client, which uses JS to append the Csrftoken code to the link and form request address in HTML, where the token is defined as a global variable and its value can be To get from the session.
Listing 3. Additional tokens on the client for the request
function Appendtoken () {updateforms (); Updatetags (); } function Updateforms () {//Gets all the form elements in the page var forms = document.getElementsByTagName (' form '); for (i=0; i<forms.length; i++) {var url = forms[i].action; If the action value of this form is null, then the csrftoken if (url = = NULL | | url = = "") Continue is not appended; Dynamically generates input elements, added to the form, 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; Traverse all a elements 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! =-1) {//url contains only the equivalent page of the anchor tag fragment = Location.substring (Fragmentindex); Location = location.substring (0,fragmentindex); } var index = Location.indexof ('? '); if (Index! =-1) {//url already contains additional parameters location = location + ' &csrftoken= ' + token; There is no other parameter in the else {//url location = location + '? csrftoken= ' + token; } if (fragment! = NULL) {location + = fragment; } element.setattribute (attr, location); } }
In the client HTML, there are mainly two places to add tokens, one is form form, the other is link a. This code first iterates through all the form, adds a hidden field to the form at the end, and puts the csrftoken into it. The code then iterates through all the link tag a, adding the Csrftoken parameter to its href attribute. Note For A.href, it is possible that the property already has parameters, or there is an anchor tag. It is therefore necessary to discuss the situation in a separate format and add the Csrftoken to it.
If your site uses XMLHttpRequest, you also need to customize the Csrftoken property in the HTTP header, using DOJO.XHR to add a custom property code to XMLHttpRequest as follows:
Listing 4. Customizing properties in the HTTP header
var plainxhr = dojo.xhr; Override dojo.xhr Method dojo.xhr = function (method,args,hasbody) { //Ensure header object exists args.headers = Args.header | | {}; Tokenvalue = ' <%=request.getsession (false). getattribute ("Csrftoken")%> '; var token = dojo.getobject ("Tokenvalue"); Put the Csrftoken attribute in the head args.headers["Csrftoken"] = (token)? token: " "; Return PLAINXHR (method,args,hasbody); };
This overwrites the DOJO.XHR method, first ensuring that the HTTP header exists in the DOJO.XHR, and then adds the Csrftoken field to the Args.headers and takes the token value out of the session into the field.
The way to choose CSRF Defense method
As discussed above, there are some restraint methods for the industry to deal with CSRF attacks, but there are pros and cons to each approach, and none of them is perfect. How to choose the right method is very important. If the site is an existing system, want to achieve a certain degree of CSRF protection in the shortest time, then the method of verifying Referer is the most convenient, if you want to increase security, you can choose not to support the low version of the browser, after all, for now, ie7+, ff3+ such a high-version browser The Referer value cannot be tampered with.
If the system must support IE6 and still require high security. Then use token to verify, in most cases, the use of XMLHttpRequest is not appropriate, token can only be in the form of parameters in the request, if your system does not support users to publish their own information, that degree of protection is sufficient, otherwise, you still difficult to prevent Tokens are stolen and attacked by hackers. In this case, you need to carefully plan the various services provided by your site, from the middle to identify those that allow users to publish their own information, separate them from other services, using different tokens for protection, so as to effectively resist the hacker's attacks on your critical services, to minimize the harm. After all, it is much less serious to delete a post than to transfer a large amount of money directly from someone else's account.
If you are developing a completely new system, the choice to resist CSRF is much larger. I suggest that for important services, you can use XMLHttpRequest to access as much as possible, so it is much easier to add tokens. In addition, try to avoid using complex logic in JS code to construct regular synchronization requests to access resources that require CSRF protection, such as window.location and Document.createelement ("a"), which can also reduce the additional token Unnecessary trouble when it arises.
Finally, remember that CSRF is not the only means of attack by hackers, no matter how tight your CSRF, if your system has other security vulnerabilities, such as cross-site domain scripting attacks XSS, then hackers can bypass your security, to expand the various attacks including CSRF, your defenses will be like a dummy.
Summary and Prospect
As can be seen, CSRF is a very harmful attack, and it is difficult to prevent. Currently, several defense strategies can withstand CSRF attacks, but there is no perfect solution. Some new scenarios are under study, such as using different dynamic passwords for each request, combining the Referer and token schemes, and even attempting to modify the HTTP specification, but these new schemes are still immature, and it will take time to formally put them into use and be widely accepted by the industry. Before this, we only pay enough attention to CSRF, according to the actual situation of the system to choose the most suitable strategy, so as to minimize the harm of CSRF.
CSRF attack and the way to deal with it