Cross-Site Request Forgery (CSRF) is an attack that tricks the victim’s browser into executing malicious requests designed by the attacker. A successful CSRF attack can force the victim’s browser to perform state-changing requests like transferring funds or changing his email address. Clearly these are attacks that need to be prevented.
Less Common But Still a Threat
As awareness of CSRF has increased, protection has become a prerequisite for bringing web applications online. CSRF attacks were demoted to 8th most important in the OWASP TOP 10 of 2013 from 5th most important in the OWASP Top 10 of 2010, while the prevalence of CSRF vulnerabilities was reclassified from “widespread” to “common.” That is absolutely a good sign indicating web applications are more commonly implementing CSRF protection techniques, the most common being anti-CSRF tokens, which is resulting in lower overall risk.
As a webmaster, however, you should not assume that you are protected from CSRF attacks when you see anti-CSRF tokens used in your web applications. Coding / implementation errors like missing input validation in frameworks and cross-site scripting vulnerabilities in open source software are quite common and lead to vulnerable applications. And there is no exception for anti-CSRF measures — they are also susceptible to coding errors. Back in 2012, even Facebook suffered a CSRF attack because anti-CSRF tokens were not handled correctly on the server side.
New Examples of CSRF Vulnerabilities
In the real-world examples I discovered and describe at the end of this article, I show implementation errors in three popular open-source programs: VanillaForums, Concrete5 and Xoops. These errors can happen for many reasons: the web developers might not have implemented the anti-CSRF token correctly, or they weren’t thinking properly about security, or they commented out the CSRF protection code by mistake.
Anti-CSRF Tokens and How They Work
Among the CSRF prevention methods, the Synchronizer Token Pattern is both the recommended method and the most widely used prevention technique. From Internet powerhouses Google, Facebook and Twitter to popular open source web applications such as WordPress and Joomla, this pattern is the measure of choice for protecting against CSRF attacks. The synchronizer token pattern requires the generation of random "challenge" tokens (anti-CSRF tokens) that are associated with the user’s current session. These challenge tokens are then inserted within the HTML forms and links associated with sensitive server-side operations. When users submit the form or make a request to the links, the anti-CSRF token should be included in the request. Then, the server application will verify the existence and correctness of this token before processing the request. If the token is missing or incorrect, the request will be rejected.
How to Test Your Implementations
As always, you could do some manual tests in your web applications. You could employ a web application scanner as well, like Qualys Web Application Scanning, which will test whether the anti-CSRF token is sufficient to protect your web application against CSRF attack.
Besides that, you should do regular manual tests and/or scans against your web applications, because the developers might comment out the CSRF token validation code accidently when adding new features.
How Qualys WAS Tests CSRF Prevention Measures
Qualys Web Application Scanning makes use of its built-in behavioral analysis capabilities to test CSRF protection measures in web applications. It creates two separate sessions to the application, each with its own anti-CSRF token, and then sends the token from each client to the session associated with the other client, thereby simulating a CSRF attack. If the manipulated requests generate valid responses, then that indicates with high reliability that the CSRF protection measures are not working correctly. While the test is simple, there is value in the ability to automate testing of your CSRF prevention measures across your applications and as part of your regression testing cycle.
With no doubt, proper implementation of anti-CSRF tokens will protect your web applications. Some pen testers are not actually testing the correctness of the implementation when they see anti-CSRF tokens deployed in the web application. Even some web scanners will determine the web application is not vulnerable once they have found anti-CSRF tokens in the page. When implemented incorrectly, CSRF protection methods are ineffective even though anti-CSRF tokens were presented in the web pages, so it is best to always test your applications.
Real-World Examples: How I Got Started
I recently joined a bounty program with thousand of other pen testers to test a real commercial web application. After playing with it for a while, I found that several pages are vulnerable to CSRF attack even though they are deploying anti-CSRF tokens. After informing the company of the CSRF vulnerability, I got this reply:
“Great find, we removed our check csrf code somewhere along the line this month, will fix asap”
I was very surprised because thousands of pen testers are working on this issue and it was not found when the CSRF code validation method was not implemented properly. My only guess is that, some pen testers were just giving up testing for CSRF vulnerability when they saw the appearance of anti-CSRF tokens in the web application.
This inspired me, and I installed some popular open source web applications in our test labs at Qualys to check whether incorrect anti-CSRF implementation is a common mistake in web applications.
Without spending too much time on it, I found three popular open source web applications, VanillaForum, Concrete5 and Xoops. All three of these applications have now fixed their code.
Example 1: VanillaForums
VanillaForums is an open source lightweight Internet forum, and almost one million websites are using this software.
Proof of Concept:
Anti-CSRF token TransientKey is used to protect against CSRF attacks. However, the server side does not do any validation on this token, which will allow an attacker to trigger the administrator to post as many discussions as he wants.
After filing this bug to the developer team of vanilla forum, I got the following response:
“Hi Daniel, looks like I did miss that one in the 2.1.5 release. I’ll get a patch ready for the next one.”
This is fixed in version 2.1.7.
Example 2: Concrete 5
Concrete 5 is an open source content management system. According to its website, it is used on more than half a million websites.
Proof of Concept
As you could find, it is using an anti-CSRF token ccm_token in the URL to protect against CSRF attacks. But the request will go through even without submitting a valid ccm_token because the server side is not validating it. That was the response from the concrete5 team after I sent them my findings:
“Most likely, we forgot to check that it is valid somewhere”
This is fixed in version 126.96.36.199.
Example 3: XOOPS
XOOPS is another open source content management system and it has won several awards according to the statement in wiki. Similar to Concrete5, it is using anti-CSRF tokens to protect against CSRF attacks. However, it also fails to validate the anti-CSRF token on the server side.
Proof of Concept
POST /phpTargets/xoops_2_5_7/htdocs/pmlite.php HTTP/1.1 Host: yourhost User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:33.0) Gecko/20100101 Firefox/33.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate Referer: http://10.10.35.22/phpTargets/xoops_2_5_7/htdocs/pmlite.php?send=1 Cookie: PHPSESSID=geg8jsmfai42rf3o1hlpgg6fn2; xoops_user54611943=0 Connection: keep-alive Content-Type: application/x-www-form-urlencoded Content-Length: 129 Data: to_userid=1&subject=CSRF&icon=icon1.gif&message=CSRF&op=submit&XOOPS_TOKEN_REQUEST=9eb7cdce0d30de2cc972da7a15198f82&submit=Submit
Parameter XOOPS_TOKEN_REQUEST is used as an anti-CSRF token to protect against CSRF attacks. But the request could be sent successfully without the existence of this parameter.
This is fixed in version 188.8.131.52.