Protection against CSRF

It’s quite difficult to protect against CSRF because you are performing actions on the attackers behalf, there are a couple of things you can do to help protect against it and I shall explain a couple of methods here.

Form tokens

Form tokens can be used to make it more difficult for an attacker to perform CSRF, an explanation on form tokens is available on a previous post. Using one will not make your site 100% secure against CSRF but it will help. Make sure a form token has a short expiry date, only valid for the user in question and is not sent using GET.

Random page names

When a user signs up to your service they can each be assigned a random URL which they use to perform any action. The random URL should only be available per session and should only be created when their username and password has been supplied.

Authentication

Asking for a username and password should always be done for sensitive operations, if authentication is required it makes it much more difficult for an attacker to manipulate a user’s actions without a valid password.

Frame breaker

They are very old school but can be very effective in protecting against iframe attacks.

if (top != self) {
  top.location.href = 'http://yoururl/';
}

Damage limitation

Amazon understand this very well and have designed their delivery system this way. For example if an attacker did manage to perform CSRF on a Amazon user to buy a book for instance, the attacker could only deliver to the user’s assigned addresses. Even changing a delivery address requires credit card confirmation. This is good system design and provides good damage limitation.

20 Responses to “Protection against CSRF”

  1. Bipin 3~ Upadhyay writes:

    Gareth,
    Wasn’t the frame-breaker broken (in ie) by Collin Jackson using “security=restricted” parameter?

  2. Gareth Heyes writes:

    Good point but the frame breaker still works in Firefox and Safari ;)

  3. Chris Shiflett writes:

    What you call is authorization is actually authentication. These are often confused. CSRF is very effective at bypassing authorization checks, because an authorized user is sending the request.

    The way Amazon references addresses makes CSRF practically impossible if you want to send the item to one of the user’s existing addresses. An exploit that does this has never existed to my knowledge, although it could be done with XSS. The CSRF vulnerability I discovered only worked on new addresses, and it required multiple forged requests. This particular exploit has been addressed by requiring re-authentication prior to adding a new address, a step that did not previously exist.

    Hope that helps.

  4. Ronald writes:

    Ah I was planning an article as well, only I have 20% ready yet I’ve wrote about it before, but this will be a big article on CSRF and probably will be my last since it will mess everything up, and break the interwebs as we know it lol :)

  5. Gareth Heyes writes:

    @Ronald

    LOL can’t wait for that one :)

    @Chris

    Thanks for the useful feedback. I’m planning to create a CSRF demo if you are interested in beta testing it or improving it. I’ve updated the article with the correction.

  6. Chris Shiflett writes:

    I’d be happy to help. :-)

  7. Shahar Evron writes:

    Why a request and user unique form token, if properly used, does not provide 100% protection against CSRF?

    What I am thinking of is:
    1. When you generate the form, you add a hidden field with a random generated string.
    2. You put that string into $_SESSION as well.
    3. When the form is submitted you try to match the token value from the form with the one in $_SESSION
    4. You only allow the form to be processed if the tokens match
    5. Whether they match or not you never reuse the same token again – you generate it when you generate the form.

    I might be making a complete fool out of myself right now, but I seriously try to think of a way to bypass this protection and I can’t.

  8. Gareth Heyes writes:

    @Shahar

    Nothing is impossible. I never call anything 100% secure ;)

    I shall be creating a CSRF demo today which will include protection against all forms of iframe attacks (even with security=restricted). The demos will include form/url tokens and a combined demo which includes all techniques.

  9. laZee writes:

    #7 Shahar: An attacker opens the form on the victims side (e.g. with xss), parses out the token (which is valid, cause the form has just been opened, the token was generated, saved in that $_SESSION and placed in that hidden field) and voila. Just imagine the attacker being a person who is sitting right in front of the victims PC. All you need is XSS and CSRF.

  10. Bipin 3~ Upadhyay writes:

    @laZee:
    I am reminded of:
    1. pdp’s comment on the same; if an attacker can XSS, why the hell would he CSRF???
    Link: http://www.gnucitizen.org/blog/preventing-csrf
    2. Johann’s article named, “Buy one XSS, get a CSRF for free?”
    Link: http://blog.thinkphp.de/archives/150-Buy-one-XSS,-get-a-CSRF-for-free.html

    @Gareth:
    I shall be creating a CSRF demo today which will include protection against all forms of iframe attacks (even with security=restricted).
    Looking forward to it?
    The M$ page on “security=restricted” says that you still have access to the DOM of the restricted frame. Did you play with the DOM for it?

  11. Gareth Heyes writes:

    Here’s the iframe one:-
    http://www.businessinfo.co.uk/labs/csrf_defend/iframe_protection.php

    Let me know if you can break it :)

  12. Bipin 3~ Upadhyay writes:

    Let me know if you can break it :)
    hehe…

    Just curious, how are you generating the javascript code to create nonce?

    One more thing. Pdp had suggested using cookie value as the nonce in his essay. Even if we are paranoid about not allowing cookie value to be cached in the browser (and other similar issues), wouldn’t a simple mutated form of cookie value be an equally good nonce?

    p.s.:At first look, I thought you are obfuscating some JS code :P

  13. Gareth Heyes writes:

    Cookies could be used here. You could execute javascript and then assign the cookie that would work and that’s how my comment spam plugin works. But I wanted a method without cookies, I like a challenge ;)

    My other post deals with the javascript/php creation and includes source code if you want to take a look:-
    http://www.thespanner.co.uk/2007/08/15/random-javascript-and-php-generation/

    obfuscating js :)

    The code could be easily be expanded upon to include other generation methods if needed.

  14. Gareth Heyes writes:

    In fact if anyone wishes to expand my javascript/php generation class let me know and I’ll include the update on my blog with credits.

    I find the whole security=restricted thing very interesting because the feature is also a security hole and to protect it you create a catch 22 situation :) e.g. You need javascript to execute the token, you need to stop javascript to prevent the frame breaker :D

  15. Bipin 3~ Upadhyay writes:

    I find the whole security=restricted thing very interesting…
    Same here.
    There’s one more thing that I’d like to ask. Considering that the src inside the restricted frame is executed as “a site in IE’s ‘restriced zone’”, which means that javascript is disabled (unless it breaks out of the window, of course), can you think some attack other than Phishing the end user.

    I hope I was clear enough. We might continue the discussion here: http://sla.ckers.org/forum/read.php?2,13324

  16. Gareth Heyes writes:

    Yeah session fixation.

    You assign the user a session which you already know the answer to. That’s why I’ve included expiry dates on the tokens.

  17. Gareth Heyes writes:

    Here’s a POC I did for MyOpenID which they’ve now fixed. They used a form token but I got round it :)

    http://www.thespanner.co.uk/wp-content/uploads/2007/06/openid.zip

    Description about it here:-
    http://www.thespanner.co.uk/2007/06/29/openid-security-issues/

    This attack is quite difficult to protect against as it uses a new window to perform the attack. If you follow the advice in the post, you will be a much more difficult target.

  18. Joseph Wilk writes:

    Is it possible to protect against CSRF without relying on server state?

    Generally I have to try and avoid using state as much as possible to try and maintain a strict REST model.

  19. Gareth Heyes writes:

    It’s hard for me to provide you advice without knowing the details of your system but I’ll have a go…

    I would say enforce a password which would solve any CSRF problem. So for example if you are accept a site request on your OpenID provider site do not allow a user to save the password. Make them enter the password on each request. The only way an attacker could exploit this is to either send the valid password or ride the user’s session.

    Let me know if that helps or please provide me with a brief description on how your site works and I’ll let you know the possible attack vectors and prevention.

  20. dblackshell writes:

    @Shahar Evron

    the token could be retrieved via dynamic script tags… a way to prevent that is by requesting a new token via AJAX when the page is loaded… on a normal form retrieval the hidden field should be blank.