Cross-site scripting attacks are becoming more and more popular amongst hackers. According to the annual OWASP Foundation Top 10 report XSS (Cross-Site Scripting) and CSRF (Cross-Site Request Forgery) attacks remain in the high on list (#3 & #6, retrospectively).
Since cybercrime is on the rise, it is imperative for organizations to secure their web applications from these types of attacks.
What is CSRF?
OWASP CSRF definition:
CSRF is a type of attack that occurs when a malicious web site, email, blog, instant message, or program causes a user’s web browser to perform an unwanted action on a trusted site for which the user is currently authenticated. The impact of a successful CSRF attack is limited to the capabilities exposed by the vulnerable application. For example, this attack could result in a transfer of funds, changing a password, or purchasing an item in the user’s context. In effect, CSRF attacks are used by an attacker to make a target system perform a function via the target’s browser without knowledge of the target user, at least until the unauthorized transaction has been committed.
Have an example?
A great example of a CSRF attack might be an attack where the victim has recently logged into their account on their bank and has a valid session up and running. While still logged in, the user is sent a fake email posing as his bank. Clicking that e-mail sends him to the attacker’s site that may be skinned to look like the bank site. In effect, that site performs a POST to the real bank’s operational endpoint for sending money, transferring money out of the victims account and into the attacker’s. Since the user’s session is still valid, the operation is accepted and the attack is successful.
Essentially, the attack is piggy-backing off of the user’s valid session that is stored in their cookies, using that as a way to access operational endpoints in the application.
How can I test my site to see if it is vulnerable?
Portswigger has a FREE tool called Burp, which has script that it generates for testing CSRF requests. Consider reviewing Using Burp to Test for Cross-Site Request Forgery (CSRF) to learn more about the tool. The way Burp works is that it monitors traffic, sniffing endpoint traffic and what params are used. From this, it generates a simple HTML page that does a form POST to the operational endpoint, attempting to make it perform an action. If the POST succeeds, you’re vulnerable to attack.
How to architect applications to prevent against CSRF attacks
The OWASP has a few suggestions for preventing against CSRF attacks. Together, both of the following options offer the highest level of protection:
- Check standard headers to verify the request is same origin
There are two steps to this check:
- Determining the origin the request is coming from (source origin)
- Determining the origin the request is going to (target origin)
- Check CSRF token
In addition to checking the request origin, OWASP suggests using a Synchronizer (CSRF) Token pattern.
From their site docs:
- Any state changing operation requires a secure random token (e.g., CSRF token) to prevent CSRF attacks
- Characteristics of a CSRF Token
- Unique per user session
- Large random value
- Generated by a cryptographically secure random number generator
- The CSRF token is added as a hidden field for forms or within the URL if the state changing operation occurs via a GET
- The server rejects the requested action if the CSRF token fails validation
When implementing this, the key is that when a session is created, the server generates a token, which is passed to the browser via a Set-Cookie header.
In effect, every time the browser makes a request to the operational endpoint on the server, this CSRF token is provided as a header in the request. Alternatively, you could add it as a param in a POST payload or a query string variable in a GET request, but personally I find this to be less clean. If the token on the server matches that on the client request token, then the request is valid and succeeds. If they don’t match, then fail with an error.
Remember that the token should be user-specific and should only be valid for the duration of the session:
OWASP’s suggestion is to only require tokens on operational endpoints that perform “any state changing operation” on the server. Personally, I think it’s safer to ensure you’re protecting all your application endpoints with the token synchronization pattern. Even GET requests have the potential to expose sensitive data.
Questions, comments? Leave them below in the comments.