35

http://seclab.stanford.edu/websec/csrf/csrf.pdf points out that most CSRF protection mechanisms fail to protect login forms. As https://stackoverflow.com/a/15350123/14731 explains:

The vulnerability plays out like this:

  1. The attacker creates a host account on the trusted domain
  2. The attacker forges a login request in the victim's browser with this host account's credentials
  3. The attacker tricks the victim into using the trusted site, where they may not notice they are logged in via the host account
  4. The attacker now has access to any data or metadata the victim "created" (intentionally or unintentionally) while their browser was logged in with the host account

This attack has been successfully employed against Youtube.

The authors of the paper went on to propose the addition of an "Origin" header but ran into resistance by W3C members: http://lists.w3.org/Archives/Public/public-web-security/2009Dec/0035.html

To date, only Chrome and Safari implements the "Origin" header. IE and Firefox do not and it's not clear whether they ever will.

With that in mind: what is the best way to protect against CSRF attacks on login forms?

UPDATE: I am looking for a RESTful solution, so ideally I want to avoid storing server-side state per user. This is especially true for non-authenticated users. If it's impossible then obviously I will give up on this requirement.

1

4 Answers 4

25

With anonymous cookies

If you are happy to generate secure tokens which are set as anonymous users' cookies, but not to store them server side then you could simply double submit cookies.

e.g. Legitimate user:

  1. Anon user navigates to the login page, receives cookie which is sent to the browser.
  2. Anon user logs in and the browser sends the cookie as a header and as a hidden form value.
  3. User now logged in.

This cannot be abused by the attacker as the following will now happen:

  1. The attacker creates a host account on the trusted domain
  2. The attacker forges a login request in the victim's browser with this host account's credentials However, the attacker does not have access to the victim's cookie value and cannot forge it as the CSRF token in the request body. The attack fails.

Even if your site is only accessible over HTTPS and you correctly set the Secure Flag, care must be taken with this approach as an attacker could potentially MiTM any connection from the victim to any HTTP website (if the attacker is suitably placed of course), redirect them to your domain over HTTP, which is also MiTM'd and then set the required cookie value. This would be a Session Fixation attack. To guard against this you could output the cookie value to the header and the hidden form field every time this (login) page is loaded (over HTTPS) rather than reuse any already set cookie value. This is because although a browser can set the Secure Flag, it will still send cookies without the Secure Flag over a HTTPS connection, and the server will not be able to tell whether the Secure Flag was set. (Cookie attributes such as the Secure Flag are only visible when the cookie is set, not when it is read. The only thing the server gets to see is the cookie name and value.) Implementing HSTS would be a good option for protection in supported browsers.

It is advisable to set X-Frame-Options to prevent a UI redress click jacking attack (otherwise the attacker could possibly use site functionality to pre fill their username and password awaiting the user to click and submit them along with the CSRF value).

Without anonymous cookies

If you do not want to set cookies for anonymous users (which then may suspect that they are being tracked server side) then the following approach may be used instead: A multi-stage login form.

The first stage is the usual username / password combination.

After the form is submitted, it redirects to another form. This form is protected by a special intermediary authentication token cookie and a CSRF token. The authentication here will only allow the second stage authentication to be submitted, but will not allow any other actions on the account (except possibly a full logout). This will enable the CSRF token to be associated and used by this user account only on this intermediary session.

Now it is only when this form is submitted, including the token cookie and CSRF hidden form value that the user is fully authenticated with the domain. Any attacker attempting a CSRF attack will not be able to retrieve the CSRF token and their full login attempt will fail.

The only drawback is that the user will have to manually click to complete login, which may be a clunky user experience. It is advisable to set X-Frame-Options to prevent this being used in combination with a UI redress click jacking attack. Any auto submission with JavaScript would be beneficial to the attacker and would cause their attack to possibly succeed, so at the moment I can only see a manual click by the user working.

It would now play out like this:

  1. The attacker creates a host account on the trusted domain
  2. The attacker forges a login request in the victim's browser with this host account's credentials but they cannot proceed past stage two to become fully authenticated
  3. The attacker tricks the victim into using the trusted site - but as they are not fully authenticated, the site will act as though the user is unauthenticated
9
  • Why do you need the intermediate step? What could happen if you omit it and simply use a Double Submit Cookie that is not associated with an authentication token?
    – Gili
    Jun 6, 2014 at 18:30
  • @Gili: Well to stop normal CSRF you associate the user session maintained by an auth cookie with something that is outside of the automatic cookie mechanism (e.g. a hidden field containing a CSRF token). So the intermediate step is needed so that this can happen before the user logs in. Without it you would be back to square one and vulnerable to login CSRF. Jun 6, 2014 at 19:33
  • I'm finding it very hard to understand you over Stackoverflow's limited commenting system. What's wrong with this? Page 1 contains a form with a hidden CSRF field and a cookie CSRF value, and username/password fields. Once the user submits the form, you the server verifies the username, password, CSRF tokens match. If everything is good, it sets an "authentication id" in a separate cookie. Henceforth, all actions that require user authentication will check for a hidden CSRF field, CSRF cookie and authentication cookie. There is no intermediate page. Now, how can an attacker break this system?
    – Gili
    Jun 7, 2014 at 2:51
  • @Gili: I now see what you mean. Sorry - I misunderstood your requirement for anonymous users - I didn't think you wanted any cookies set for them at all. It had been a long day - answer now updated for clarification. Jun 7, 2014 at 8:43
  • @Gili: Info added on how to avoid a Session Fixation attack with the anon cookie method. Jun 9, 2014 at 13:29
4

So a slightly niche requirement, but hey a valid CSRF. There's a couple of choices of how you can address this that spring to mind

  • Standard anti-automation techniques like a CAPTCHA. Of course not the most user friendly of solutions but can help mitigate other attacks at the same time.
  • Have a standard Anti-CSRF token which is tied to information provided by the client which is available pre-authentication. An obvious option would be to tie it to source IP address. That's not perfect (systems behind proxies would have the same address) but would reduce the risk quite a bit. Another option would be to tie the token to specific browser identities. If you look at Panopticlick you can see that browsers provide identifying information so it might be possible to create a fingerprint based on that and issue one Anti-CSRF token for each fingerprint which contacts the site. Again not perfect but makes the attack harder to execute.
2
  • Your answer is technically the safest and most flexible, so I'll up-vote it. However, because I control all sub-domains I believe the Double Submit Cookies mechanism will be much easier to implement and will be just as secure.
    – Gili
    Jun 5, 2014 at 20:12
  • 2
    Don't forget that Attacking site A has access to the same browser-identifying information as your site. Jun 27, 2014 at 12:23
2

I'd like to propose a variant of the Encrypted Token Pattern which works as follows: When a client requests an HTML page needing CSRF protection...

  1. The server checks for the existence of a sessionId cookie. If it is missing, the server sets a new HttpOnly cookie containing a cryptographically-strong pseudorandom value. Note this value is not stored on the server but it still protects against login CSRF (an attacker cannot authenticate without passing through the login form).
  2. If the user is logged out, return an HTML page that triggers authentication for unsafe operations. Go back to step 1.
  3. If the user is logged in, the server encrypts [sessionId + nonce] using a secret key and embeds the value (which we shall call csrfToken) into the HTML file. It isn't important where csrfToken is embedded, so long as the Form or Javascript function making the request can access it. nonce is a cryptographically-strong pseudorandom value used to prevent brute-force attacks on the secret key, but is not used during the validation process.
  4. Forms submit csrfToken using a hidden field of the same name. Javascript functions submit csrfToken using a custom request header named csrf-token.
  5. The server decrypts csrfToken and compares its value to sessionId. If the two don’t match, the server returns 401 Unauthorized and triggers authentication.
7
  • Looks good on first look. Jun 27, 2014 at 12:48
  • @SilverlightFox, do you think this approach provides any security benefits over double-submit cookies? It is more computationally expensive, so unless it adds security I think I'll stick to double-cookies.
    – Gili
    Jun 27, 2014 at 18:36
  • Yes - it would stop an attacker from setting any cookie themselves as they do not know the encryption key. Jun 28, 2014 at 11:55
  • 1
    Yes it is. I've commented on this in my other answer - a MITM attack on a HTTP cookie that will be read by the site over HTTPS - the site cannot check that the Secure flag was set as it only receives the name and value. HSTS can help but not yet supported by all browsers, and you might have to have it pre-loaded in the browser address list otherwise an attack may be possible before the first request. Jun 28, 2014 at 19:54
  • 1
    Yes I guess if an attacker could write cookies they could just write a logged in session cookie to achieve login rather than via csrf. Jun 29, 2014 at 20:48
0

You can apply any of the standard anti-CSRF techniques, be it the Synchronizer Token Pattern or Double Submit Cookies. The former is generally more secure, because cookies can be overwritten by subdomains.

You claimed that the Synchronizer Token Pattern only works after authentication, but this is not the case. An attacker does not have access to the token of a user, regardless of whether the user is authenticated or not.

Of course the attacker can visit the login page herself and obtain a valid anti-CSRF token. But this token only works for the attacker. If the victim makes a request, then the token is not accepted, because it's not present in the victim's session. In fact, the session will be entirely empty on the first request.

8
  • You are assuming the existence of a server-side state for non-authenticated users, which is a big no no for me. I will amend the question to clarify this requirement.
    – Gili
    Jun 5, 2014 at 16:53
  • What I'm saying is that from a security perspective, all approaches can be used with or without authentication. If you rule out the Synchronizer Token Pattern based on a design decision, well, then you'll have to go with Double Submit Cookies and accept the additional risk. I'm not aware of any other techniques.
    – Fleche
    Jun 5, 2014 at 17:13
  • According to webstersprodigy.net/2012/08/03/… neither Double nor Triple Submit Cookies are safe. I'll keep on looking.
    – Gili
    Jun 5, 2014 at 17:36
  • I just had another thought. Even if I assign sessionId to unauthenticated users, what prevents the attacker from crafting a malicious form that submits using his sessionId and valid Synchronizer Token? Meaning, I believe this is open to the same attacks as the Double Cookie Submit approach (e.g. using XSS on a subdomain to override the sessionId value or simply passing it as a query parameter).
    – Gili
    Jun 5, 2014 at 17:37
  • 2
    Okay, allow me to clarify: 1. This question is primarily concerned with login attacks. In that context, I believe the two approaches are equally secure. 2. This question favors stateless mechanisms. In light of this, I favor the use of DSC if we control all sub-domains, followed by security.stackexchange.com/a/59413/5002, followed by STP if server-state is acceptable. While it is true that STP is superior to DSC if you allow server-state, the question requirements make it less desirable.
    – Gili
    Jun 5, 2014 at 20:52

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .