Friday, October 9, 2009

XSRF/CSRF Vulnerability Explained in Non-Geek Speak

I recently explained what cross-site request forgery (CSRF/XSRF) is to a friend who isn't a programmer/CS person and I was pretty amazed at how quickly he understood the implications of not protecting against such attacks. With the proliferation of social interactions on the web now, such attacks can be pretty damaging to consumers of new media and e-commerce sites.

The Wikipedia article about CSRF does a pretty good job of explaining the issue - most people familiar with web development should be able to understand it easily. Basically, this attack lets legitimate unsuspecting users submit changes to a site they routinely interact with, but without their knowledge. CSRF attacks leverage your own browser and the trust you associate with it to perform potentially damaging actions on your behalf.

Here's an example of what such an attack might look like. Let's assume that Facebook wasn't protected against such attacks, for the purpose of this illustration. In reality, I'm sure Facebook engineers have done a good job of making sure this can't really ever happen. That's not true of every site out there, though.

When you sign into Facebook, you have the option of remaining signed in. To do this, sites like Facebook set a browser cookie which identifies you to their servers. This is great because it lets you visit the site frequently and navigate the site without needing to enter your password every time. Browsers are good about securing your cookie - they make sure that no other site besides Facebook can see this cookie, so it's not possible for the author of www.hacker.com to steal your cookie and present it to Facebook and then impersonate you. However, each time you go to any URL that contains www.facebook.com, the browser diligently sends over all cookies associated with Facebook, because the receiver of those cookies is www.facebook.com.

Once on Facebook, you do things like update your status or write on a friend's wall. When you do that, the browser sends your new status update to Facebook along with the cookies. By inspecting the cookie, Facebook is able to validate that it is indeed you trying to update your own status, so it proceeds to allow the action. Under the covers, your browser is sending over two pieces of information - some data (your status update text, in this case) and the cookies. The browser was triggered to do this by you clicking the "Submit" button. This sounds pretty straightforward so far.

Now imagine you're browsing the web and land on this page that talks about world hunger and how you can help the cause by simply clicking a "Help the Children" button. With only altruistic intentions, you click on the button. Nothing visible happens, or maybe a "Thank you!" label replaces that button. Then you simply move on to the next thing you were going to do. Suddenly, you start receiving email notifications about friends responding to your latest status update on Facebook, except you never posted any update. You visit Facebook and sure enough your status now says "I am a loser!", updated 2 minutes ago. Huh?! You didn't set that status. You panic - maybe someone hacked your account? Or someone guessed your password? What's going on?

What really happened was that the world hunger website you were on was written by a malicious attacker, and when you clicked the "Help the Children" button that website didn't really contribute 10 cents to UNICEF, but instead told your browser to send a new status update with the text "I am a loser!" to www.facebook.com. This site couldn't access your cookies directly, so the browser didn't do anything bad and stuck to its promise of not letting anyone else see cookies that shouldn't be visible to them. Remember, the attacker never looked at your cookie at all while any of this happened. However, when the attacker asked the browser to send data to www.facebook.com, the browser added the Facebook cookies to the request. So now Facebook looks at the cookies and the data, thinks that it is indeed you and goes on to update your status. Boom!

So what went wrong here? The browser didn't do anything bad - it did exactly what it's supposed to. It hid your Facebook cookies from everyone except Facebook and it sent data that submitting the "Help the Children" button asked it to send. You didn't do anything bad - you simply clicked on a link that was meant to help needy kids. You did have cookies enabled (default for most browsers) and decided to check that "Log in automatically" option, but those seem like reasonable actions.

The flaw here is with the website you trusted - Facebook, in this example. Sites like Facebook that rely on cookies to identify and authorize user actions need to do more things than just validate your cookie when data is presented to the site on your behalf. They need to make sure that place from which the data was sent was 'good', or that a malicious author cannot create data the same way that www.facebook.com can. They need to make sure that when you update your status, the data contain more than just your new status text - there must be some kind of secret information in there that can only be generated by Facebook, and this secret must be different for each Facebook user. They can even control how long cookies and secrets remain valid, and have ways to periodically require users to sign in and generate new unique secrets for users.

Of course, this is just a silly example. I'm sure Facebook is perfectly adept and handling such attacks. However, a vulnerability like this could impact everything from online review sites to banking and e-commerce sites. It's always good to be aware of things that could go wrong online - the Internet is definitely not as safe as you might think it is.