Feed Sign in with OpenID OpenID

Simon Willison’s Weblog

Django: Security fix released. The Django admin used to save partially-submitted forms if your session expired, and continue the submission when you logged in. It turns out that’s actually an unblockable CSRF exploit and is hence broken as designed, so it’s now been removed. Thanks Ed Eliot and other GCap colleagues for helping me flesh out the potential attack.

Tagged , , , , ,

8 comments

  1. And unless I'm misreading the logs, it seems a certain developer with initials "SW" was the one who came up with the feature in the first place... did you really get to be both the cause of, and solution to, a security issue? ;)

    James Bennett - 3rd September 2008 01:49 - #

  2. This may be an unrelated issue, but there's no reason the CSRF middlelayer needs the session id or any involvement with the authentication layer. The CSRF just needs to be a random value (updated at some interval--a week or so is reasonable).

    Bill Zeller - 3rd September 2008 03:21 - #

  3. James: quite probably. I know I fleshed it out with Adrian, but there's a decent chance the original implementation is mine. I don't think I even knew what CSRF was back then.

    Bill: CSRF protection is no good if it's tied to a token which is the same for every user of your site, because that means an attacker can log in once with his own account, grab the global CSRF token and use it to construct an attack against another user. The token needs to be unique to the individual user to prevent an attacker from creating their own token that works for someone else. The session ID is just the easiest way of doing that.

    Simon Willison - 3rd September 2008 07:39 - #

  4. Simon: Right, it shouldn't be the same for each user. It can, however, be set randomly for each user without taking the session id or other authentication information into account.

    Flow:

    1) User visits site and is assigned cookie containing random nonce.

    2) When user loads a page containing a form, that nonce is written to the HTML of the form.

    3) When a POST form is submitted, the nonce in the cookie is compared to the nonce in the form.

    An attacker can generate his own random nonce (by visiting the page), but he cannot predict what a user's nonce will be. He also can't read the source of the page that the user sees. The attacker can't find the user's nonce, and cannot submit a form that will validate.

    I don't see the need to tie this to a session id and not doing so would separate the CSRF middlelayer from the authentication libraries and possibly fix the problem this post describes.

    Bill Zeller - 3rd September 2008 14:47 - #

  5. You're right, a random cookie would work in place of a session ID - the only reason we use the session ID is that it saves us having to serve up another cookie, but decoupling CSRF protection from sessions is definitely a worthy goal.

    It wouldn't solve the stashed CSRF problem though (I really need a snappy name for this kind of attack). The problem with this attack is that it takes advantage of a feature designed to ensure a POST can continue even if the user's session / cookies / etc have been lost. That's the very definition of a CSRF attack, so the feature itself is fatally flawed.

    Simon Willison - 3rd September 2008 17:05 - #

  6. That's a good point. It seems like you could set the CSRF cookie for much longer than the login cookie (an attacker would have to iterate over random nonces while the victim was on his page which would take a very long time to do anything meaningful). This wouldn't help if cookies would deleted, but would help if the user's session expires.

    Bill Zeller - 3rd September 2008 17:21 - #

  7. Is the actual attack outlined anywhere? I have added a feature that sounds similar into my day job web app, but I'm not using Django. I would like to be able to tell whether my code suffers from this vulnerability as well.

    Aristotle Pagaltzis - 26th September 2008 05:22 - #

  8. Isn't the problem with setting it in a cookie rather than in the form request that an attacker won't have to spoof it, since the attacked site will be able to read the cookie it set, even if the request comes from somewhere else?

    I'm banging my head against similar issues at the moment.

    eric casteleijn - 29th October 2008 10:40 - #

Comments are closed.
A django site