Secure Coding 101: Remediating CSRF Vulnerabilites
Cross-Site Request Forgery (CSRF) attacks have been around for a long time, but even today some frameworks and web applications do not implement measures to mitigate this attack vector. From an attackers perspective CSRF attacks can be a bit elaborate and time-consuming, because for the attack to work, the attacker first needs to lure the victim to her website (e.g. via a phishing email), all while the user has an open authenticated session on the target application. If it works however, the attack pays off handsomely: A transaction of the attacker's choosing is executed, such as creating a new user account on the target system.
The following examples show the best practices to prevent CSRF attacks as well as common mistakes that should be avoided.
Note: This article presupposes that the reader is familiar with the technical details of CSRF attacks. For those who want to learn more about the attack, I suggest reading the attack description on OWASP.
Creating and Validating a Token
To prevent CSRF attacks you need to do the following:
- create a random and unique token via an cryptographically secure random number generator
- store it on the server-side and tie it to the users current session
- sent the random token with all forms that trigger state changing operations (such as creation of a new user account or creating an order in an online shop)
- ensure that the token sent by the client when posting the form is identical to the one stored on server side before executing the state changing operation.
If the token is submitted and verified before any state-changing actions are executed, CSRF attacks are effectively prevented. The attacker's only option would be to exploit an XSS issue to read the token out of the DOM (so don't forget to prevent XSS as well).
Use Existing Solutions
As is often the case in security, reinventing the wheel is not a good idea. Whenever possible, rely on standard mechanisms that are already available within your framework and activate and/or configure them according best practices. Some frameworks, like Vaadin (Java) already have a CSRF protection mechanism built in and actived by default. Here are some other examples of popular frameworks and programming languages that already have solid mechanisms to prevent CSRF attacks you simply need to enable:
If your framework of choice does not offer any mechanisms to address CSRF vulnerabilites or you are working with legacy code, try to include an anti-CSRF library to add the protection. Again: If you try to reinvent the wheel, chances are high you will fail. Better rely on a proven existing system, such as the OWASP CSRFProtector Project.
If for some reason you need to implement the CSRF protection mechanism on your own, avoid the following pitholes that we sometimes encounter during penetration tests:
1. Use a POST request when sending the token to the server and use the POST body for the token. If the token is sent in the URL the token is disclosed all the way to the target server in the browser history, proxies and finally in the log file of the webserver. Some frameworks generate one random token per session, so disclosing the token might provide the attacker with an attack window.
2. Verify the content of the token parameter and the existence of the token parameter itself on server side. It might sound like a no-brainert but we have actually encountered some cases where simply not sending the token would bypass the protection.
3. Verify that the token is tied to the user's session on server side. A CSRF token generated for user X should only be valid for user X. Otherwise an attacker with a valid user account can easily bypass the protection by using his own token to create a CSRF exploit and attack other users of the system.
Rely on standard libraries when implementing countermeasures to prevent CSRF attacks and use them comprehensively throughout your application. When there is a need to implement CSRF protection on your own, follow the best practices in the OWASP CSRF Prevention Cheat Sheet.
Are you ready for a challenge?
Put your secure coding skills to the test by solving the OWASP Top 10 Levels on Bugrank, our community based challenge website!