Friday, March 30, 2012

CSRF Is A Vulnerability In All Browsers

Navigation:
#1 CSRF Is A Vulnerability In All Browsers - You MUST Deny It ASAP.
#2 top secret(will be published on April 1)
#3 Another Rails Issue(April 2-3)
#4 The Webkit Hole(April 2-4)

It took me a long time to understand the point behind CSR (cross-site requests) and CRSF fully enough to find them EXTREMELY malicious.
Following points should be made before any explanation.
  • It is well known attack(yep, just like mass assignment). It's known but not well. You won't find any mention of CSRF in books for beginners a la "PHP in 24 hours" or "HTML/CSS for dummy". Underestimated kind of attack.
  • It is neither bug in OS nor in browser nor in the servers' adjustments. Linux/Mac/Windows, Chrome/Firefox/IE - it just doesn't matter! This is just an expected behavior. And it works like it supposed to. Funny, isn't it? Known since 2001 but not fixed yet. Interested? Keep reading.
  • HTTPS? Would not help. SSL has nothing to do with this attack.
  • Short sessions? Sounds nice, but there are always a few ways to ask/force user to sign in and than script can attack. We are human, it's not so difficult to cheat on us. And, short sessions are rare, most sites with a "remember me" button do not rely on short sessions.
  • Special plugins/extensions to be secure(e.g. https://www.requestpolicy.com/). Who uses them?! O_o Almost nobody.
  • Protection on server-side. Rails 3 framework has it out-of-box - using authenticity_token helps. By the way Rails is the most secure framework I've ever seen.(sic!) Mass assignment is "vulnerability" in the documentation and developers are in charge; but not in rails. At the same time to have protection with other langs/platforms(PHP, Java, Asp.net) you have to write ~10-50 additional lines of code. IMO(and *these cases* prove it) 90% of developers just don't care and don't spend time on that. That's a huge hole, easy to find and easy to use.
The backbone.
There is site1.com. It could be anything: blog, social network like facebook/twitter/google+ or even payment system. You have an account on this site.
1. You are remembered with cookies mechanism.
2. Site has short sessions. Hacker asks you to sign in anyhow. E.g. the banner "you won 1 dollar for visiting this page, check your %payment _system%!" and in a few seconds after you signed in hacker's page fires up the malicious script.

So, you are signed in.

You visit site site2.com(with funny pictures, free mp3 or pr0n). No matter how you got there - let's assume friend gave you the link.
That site sells "iframe traffic"(or just contains malicious code itself). It means that funny site uses your browser(and your accounts on all sites where you are logged in!!).  You know nothing and notice nothing. Hidden iframe loads malicious Javascript which executes POST(or GET/DELETE/PATCH etc - all HTTP Verbs are supported) by submitting generated <form> with specific params. Form's action points to site1.com/someaction, form's target - name of another hidden iframe. Then, code fires up formObject.submit(). It is manual form submitting.
What has happened? "You"(in fact "your browser") just sent request to site1.com/someaction with all needed cookies(browser attached them automatically) with (definitely malicious) params - for example "spam blog post", "start following another spam account" or even data for withdrawing money to hacker's bank account(sic!) - anything.
Server side has no idea that you are not "you" - it looks the same. And Application executes your request just like it was you who made a request. You didn't notice anything.

One day you will, for example, check list of your followings and find there unknown strange accounts named like "viagra_buy_online_ca" or "celitra_no_prescription" lol. Or find out that few days ago you tweeted "Earn 10 Dollars Per Second Super Technique Blah Blah link.com/referal". (sent not via twitter.com but approved apps like vulnerable YFrog)

Prevention.
It is the common case described above. Of course sites like google, twitter, facebook etc most likely are protected from this attack. But not necessary! Protection requires additional efforts - this is why so many websites are CSRF-vulnerable.

I so much enjoy the following quote from the previous shit storm:
Insecure-by-default means "insecure"
Exactly, the same thing here. By default your app is insecure.

If your apps consume requests w/o verifying authenticity token for each POST/GET/... request - you are vulnerable. For each, every time.
Yeah, you can check 'referer' every time but it involves additional regexp/rules and looks so lame to me, this is not a panacea at all.

What do I suggest.
A compromise. We cannot deny the technique right away for a lot of reasons - backwards compatibility, most ads and analytics engines use it - denial will break tons of code in the internet, and sometimes it's really useful and needed thing etc.

Look at the pictures:







These are default top bars in chrome and firefox for some actions that could potentially be malicious. I suggest to make a similar one e.g.:

*This page %hackersite.com% submits data to an external resource %paymentsystem.com%! What to do?*
[button Accept]
[button Decline]
[check box - add the resource domain to whitelist(for stats and ads)]

But it should be denied by default and request should be sent only if user accepts it.

Again, kind of conclusion: CSRF is not a vulnerability in apps. It is a HUGE HOLE in browsers. And this damn hole makes us, developers, to invent wheel such stupid things like csrfmiddlewaretoken compulsory IN EVERY REQUEST. Imagine milliards of HTTP requests and each contains sort of  "9f38ada5f4e2c62ca8550071c2c44a0796be8c40" thing + tons of checks cookie[token]=params[token]. What a fail?! It's you job, dear browser, to handle requests and SameOriginPolicy stuff. What a workaround?! Are you kidding us, honey?

We(browsers+developers+w3c etc) must find the best solution of the issue and fix it. OK, I know in before you won't listen to the speech. Words don't change the way how web browsers work. *Here are actions*.

This change will dramatically make the Internet 80%(And this is not a random number but pretty real percent of "vulnerable" sites) more secure and safe! Let's solve the issue once and for all ASAP.


References:
http://www.codinghorror.com/blog/2008/10/preventing-csrf-and-xsrf-attacks.html - in 2008 youtube had no protection at all. Do you still think it's newbies' mistake? Jeff Antwood SHOUTED about CSRF. What has changed since 2008? Nothing. Youtube is safe but thousands of new startups aren't.
https://github.com/rails/rails/blob/master/actionpack/lib/action_controller/metal/request_forgery_protection.rb - that's how rails rockstars got rid of the issue by default.
https://media.blackhat.com/bh-eu-12/shah/bh-eu-12-Shah_HTML5_Top_10-Slides.pdf - slides from recent black hat conf
http://pentestmonkey.net/blog/csrf-xml-post-request - don't rely on custom Request Payload. The same thing with json's payloads.
https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)_Prevention_Cheat_Sheet#Checking_Referer_Header - RTFM

tbc

P.S. the first post contains only theory. Please, stay tuned until April 1 and you will get lulz info

16 comments:

  1. Unfortunately using cross-site form posts, is really useful for certain types of applications, particularly where you want a central form driving (for example) several back-ends which are selected by some client-side mechanism.

    Adding this kind of "security panic" message to legitimate sites, is going to make people go a bit crazy and start raising dodgy support tickets.

    ReplyDelete
  2. The problem is that doing so would break most of the current "Web 2.0"/everything-as-a-service sites.

    I've tried Request Policy, but uninstalled it the same day because of this - most sites routinely do tons of external requests and you can either block everything and break features or spend tons of time considering what to allow and what to deny.

    ReplyDelete
  3. If you used an iframe instead of img, wouldn't the X-Frame-Options: SAMEORIGIN block this kind of CSRF "attack"?

    What if browsers implemented a kind of hotlinking protection via http header, like X-Image-Options: SAMEORIGIN ? This would block your trick.

    ReplyDelete
  4. @mark no, I would feel more secure. It's bettter than it is now

    @daniel. You exaggerate. Not so many external requests as it seems

    @f055 NO.

    ReplyDelete
  5. @Egor, could you elaborate? you say browsers should "handle requests and SameOriginPolicy stuff" - so why not create more sameorigin http headers (for images, forms etc.)?

    ReplyDelete
  6. @Egor disregard my last comment, I figured out my mistake. headers get returned after the request is made, so it doesn't matter.

    ReplyDelete
  7. Nice read, just wanted to mention that "sic" usually stands for "spelling as in original": http://en.wikipedia.org/wiki/Sic

    ReplyDelete
  8. If you start opening up "Load 3rd party content" warnings for all cross site requests, there would be a lot of problems with sites just accessing images, javascript, and css from third party sources.

    A major share of the web uses one of the few major cdns for jquery. All of these would be counted as cross site requests. Should browsers display a warning before opening all of these sites? Definitely no.

    The solution does not lie in breaking the web from the browser, but a different angle.

    ReplyDelete
  9. >> By the way Rails is the most secure framework I've ever seen.

    What about Lift web framework. Here is a citation form their website: >> Lift apps are resistant to common vulnerabilities including many of the OWASP Top 10

    For example try to deal with StackMob or Foursquare - very interesting if you will be able to crack them too?

    ReplyDelete
  10. @Anton
    Well tell me which sites are written in scala with lift - i could give it a shot.
    In fact lift and rails are both protected well.

    ReplyDelete
  11. Contrary what you said, PHP's Symfony1 framework have had automatic protection of mass asigment and CSRF for ages.

    ReplyDelete
  12. Egor, have you manage to penetrate StackMob or Foursquare yet?

    ReplyDelete
  13. @anon
    I am learning lift now. So I will try it very soon, thanks

    ReplyDelete
  14. Do I also need to protect GET request with token, or just don't do modification actions when using it?

    I found one site that use GET for everyting and relay heavyly on referer header. I seems very strange to me.

    ReplyDelete
  15. @ju
    two ways. 1 . you protect GET with token. it's ok but dirty. 2. you don't use GET for state changing requests.

    If site relies on referer try to find some hole in site to send request with its referer. insert < img >

    ReplyDelete