Overview
Cross-Site Request Forgery (CSRF) is an attack that forces an end user to execute unwanted actions on a web application in which they’re currently authenticated. CSRF attacks specifically target state-changing requests, not theft of data, since the attacker has no way to see the response to the forged request. With a little help of social engineering (such as sending a link via email or chat), an attacker may trick the users of a web application into executing actions of the attacker’s choosing. If the victim is a normal user, a successful CSRF attack can force the user to perform state changing requests like transferring funds, changing their email address, and so forth. If the victim is an administrative account, CSRF can compromise the entire web application.
How does the attack work?
There are numerous ways in which an end user can be tricked into loading information from or submitting information to a web application. In order to execute an attack, we must first understand how to generate a valid malicious request for our victim to execute. Let us consider the following example: Rex wishes to transfer Rs. 100000 to Deepak using the mannaranbank.com web application that is vulnerable to CSRF. Joseph, an attacker, wants to trick Rex into sending the money to him instead. The attack will comprise the following steps:
building an exploit URL or script
tricking Alice into executing the action with social engineering
GET scenario
If the application was designed to primarily use GET requests to transfer parameters and execute actions, the money transfer operation might be reduced to a request like:
GET http://mannaranbank.com/transfer?acct=Deepak&amount=100000 HTTP/1.1
Joseph now decides to exploit this web application vulnerability using Rex as his victim. Joseph first constructs the following exploit URL which will transfer Rs.1000000000 from Rex's account to his account. He takes the original command URL and replaces the beneficiary name with himself, raising the transfer amount significantly at the same time:
http://mannaranbank.com/transfer?acct=Joseph&amount=1000000000
The social engineering aspect of the attack tricks Rex into loading this URL when he's logged into the bank application. This is usually done with one of the following techniques:
sending an unsolicited email with HTML content
planting an exploit URL or script on pages that are likely to be visited by the victim while they are also doing online banking
The exploit URL can be disguised as an ordinary link, encouraging the victim to click it:
<a href="http://mannaranbank.com/transfer.?acct=Joseph&amount=1000000000">View my Pictures!</a>
Or as a 0x0 fake image:
<img src="http://mannaranbank.com/transfer.?acct=Joseph&amount=1000000000" width="0" height="0" border="0">
If this image tag were included in the email, Rex wouldn’t see anything. However, the browser will still submit the request to bank.com without any visual indication that the transfer has taken place.
POST scenario
The only difference between GET and POST attacks is how the attack is being executed by the victim. Let’s assume the bank now uses POST and the vulnerable request looks like this:
POST http://mannaranbank.com/transfer HTTP/1.1
acct=Rex&amount=100000
Such a request cannot be delivered using standard A or IMG tags, but can be delivered using a FORM tags:
<form action="http://mannaranbank.com/transfer" method="POST"> <input type="hidden" name="acct" value="Joseph"/> <input type="hidden" name="amount" value="1000000000"/> <input type="submit" value="View my pictures"/> </form>
This form will require the user to click on the submit button, but this can be also executed automatically using JavaScript:
<body onload="document.forms[0].submit()">
Other HTTP methods
Modern web application APIs frequently use other HTTP methods, such as PUT or DELETE. Let’s assume the vulnerable bank uses PUT that takes a JSON block as an argument:
`PUT http://mannaranbank.com/transfer HTTP/1.1` `{ "acct":"Rex", "amount":100000 }`
Such requests can be executed with JavaScript embedded into an exploit page:
<script> function put() { var x = new XMLHttpRequest(); x.open("PUT","http://mannaranbank.com/transfer",true); x.setRequestHeader("Content-Type", "application/json"); x.send(JSON.stringify({"acct":"Joseph", "amount":1000000000})); } </script> <body onload="put()">
Fortunately, this request will not be executed by modern web browsers thanks to same-origin policy restrictions. This restriction is enabled by default unless the target web site explicitly opens up cross-origin requests from the attacker’s (or everyone’s) origin by using CORS with the following header:
Access-Control-Allow-Origin: *