Hacker News new | past | comments | ask | show | jobs | submit login

No. Let me try explaining the simplest possible version of this attack.

Your bank (http://victim.com) is running its external-facing web application on Ruby on Rails. If you send a POST request to http://victim.com/transfer, you can transfer money to another person (the recipient is specified in the POST body).

The attacker sets up the following things on attacker.com:

1. A page that replies with 307 redirects to a specified destination

2. A Flash applet that makes POST requests

3. A page embedding that applet

The attacker sets the applet as if it were making a POST request to http://victim.com/transfer, setting the X-Requested-With header to bypass CSRF protection. But instead of POSTing directly to victim.com, the attacker POSTs to the redirect script.

So the end result looks something like this:

1. Flash checks to make sure that it can make requests to attacker.com (via crossdomain.xml, or by the same origin policy). It can.

2. POST request to attacker.com/redirect is made

3. attacker.com/redirect says "307, the request should go to http://victim.com/transfer

4. Flash says "OK" and makes the same request but now directed at victim.com

5. After the request has been made, Flash checks the crossdomain.xml file and says "whoops, shouldn't have made that request: you can't see the response."




Good explanation, thanks.

The part I don't understand is the POST hitting the victim app. I don't know django but rails apps require an authenticity token to be included in all non-GET requests. How does the attacking app satisfy this token check?


The bug was that Rails didn't check for the authenticity token in case of requests that were labeled as XmlHttpRequest (i.e., Ajax), and the redirect-from-flash game allows the attacker to forge the label. The fix makes it check in all cases; this is why it comes with stuff that you're supposed to patch into your layouts and application.js to put authenticity tokens into all your Ajax calls.


Rails WAS configured to accept the token OR a custom header, relying on the fact that custom headers can't be created cross domain. The patch fixes this, by requiring BOTH. Hmmm... So how do they know what the custom header is? Are they typically static?


The CSRF token is generated and stored in the user session, so rather than just X-Requested-With: XMLHttpRequest, you now also get an X-CSRF-Token: <some token stored in the user session>.

Rails doesn't check for XRW anymore; it just cares that you passed a valid CSRF token through, either as a POST variable (normal POST/PUT/DELETE) or in the X-CSRF-Token header (AJAX).

In case you're wondering, yes, this does make caching with Varnish a bitch and a half.


I want know how the exploit works. The Flash app has to write a custom header. How does it know the value to put in the header, unless it's always the same for all sessions across all users.

P.S. You cache POST/PUT/DELETES?


That's the point of the fix. The header is custom per user now. Before, the presence of the "X-Requested-With: XmlHttpRequest" header was enough to let Rails assume the request was legit. Since Flash doesn't respect the victim's crossdomain.xml, this is no longer a valid assumption, and you have to use a unique header per session.

This means writing this unique value out into the page somewhere, to be included with any AJAX requests, which means that you cannot cache these pages as you might before, since AJAX calls would fail for everyone except the person who populated the cache.


If you cache the page from which a user submits a POST/PUT/DELETE, how are they going to get their CSRF token?


That's the point of the fix: X-CSRF-Token requires the CSRF token, which is per-user, as its value. X-Requested-With, the old way of doing things, just had to be present in the request.


The exploit SWF just puts in that it is an Ajax call:

X-Requested-With: XMLHttpRequest

which says "I'm an AJAX request". Since the value is static, it is easy to use in an exploit.


The user would first have to go to the attacker.com phishing site though right?

It sounds like it makes phishing scams a lot easier.

(thanks for the explanation btw)


My reading is that it's not necessarily phishing because they wouldn't need to ask the user for any information. All that would be required is for the user to be signed into the targeted webapp.

It could be totally automated. But, since the attacker doesn't get the response, they couldn't necessarily do anything with that. That doesn't make this any less dangerous, as in the bank example, you don't necessarily need to see that your transfer was successful in order to get the money.


    <embed src="http://attacker.com/evil.swf></embed>
is all that you need to execute this attack in your browser. An attacker can hide the applet via CSS and put it on a legitimate looking page. All the target needs to do is be logged in.


If you want to be super evil about it you could also embed the evil POSTing code in a swf that looks like an unevil ad and then let an unsuspecting ad network distribute it for you.

Edit: grammar.


Correct. Put it up using Google Adwords or a similar network, make sure attacker.com has a proper crossdomain.xml file (because the SWF won't be served from attacker.com), and you have a working exploit that can be deployed all over the Internet.




Consider applying for YC's Spring batch! Applications are open till Feb 11.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: