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.

Gili
  • 2,149
  • 3
  • 23
  • 41
  • 2
    [`Origin` HTTP header is implemented in Firefox and IE now](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Origin#Browser_compatibility) – Xenos Jun 29 '18 at 14:30

4 Answers4

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
SilverlightFox
  • 33,408
  • 6
  • 67
  • 178
  • 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 06 '14 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. – SilverlightFox Jun 06 '14 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 07 '14 at 02: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. – SilverlightFox Jun 07 '14 at 08:43
  • @Gili: Info added on how to avoid a Session Fixation attack with the anon cookie method. – SilverlightFox Jun 09 '14 at 13:29
  • Are you saying that when a server receives a cookie, the only attribute it can tell is the name/value? All other attributes (e.g. path, secure, etc) are only visible when the cookie is set, but not when it is read? – Gili Jun 09 '14 at 14:29
  • @Gili: Exactly. – SilverlightFox Jun 09 '14 at 16:06
  • I posted another approach at http://security.stackexchange.com/a/61972/5002. Please let me know if I'm trying to be too clever for my own good :) – Gili Jun 27 '14 at 07:32
  • I am curious if .Net's antiforgery's implementation is close to double-submit cookie. Their token and their cookie appear different but I guess the filter matches them up (doing some decryption or hashing). Then it's amazing that it should be safe to use .Net antiforgery throughout the app, including the login action (except that session invalidation on login should take care of copying the token and that some load-balancing sticky session with in-process store fails to match the token from time to time). – eel ghEEz Mar 30 '20 at 16: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.
Rory McCune
  • 60,923
  • 14
  • 136
  • 217
  • 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](http://security.stackexchange.com/q/59470/5002). – Gili Jun 05 '14 at 20:12
  • 2
    Don't forget that *Attacking site A* has access to the same browser-identifying information as your site. – user2428118 Jun 27 '14 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.
Gili
  • 2,149
  • 3
  • 23
  • 41
  • Looks good on first look. – SilverlightFox Jun 27 '14 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 '14 at 18:36
  • Yes - it would stop an attacker from setting any cookie themselves as they do not know the encryption key. – SilverlightFox Jun 28 '14 at 11:55
  • @SilverlightFox, Is the CSRF protection mechanism really relevant in the face of an attacker who can write cookies? I mean, doesn't it open me up to [session fixation attacks](http://en.wikipedia.org/wiki/Session_fixation#Attacks_using_cross-subdomain_cooking)? – Gili Jun 28 '14 at 18:38
  • 1
    Yes it is. I've commented on this [in my other answer](http://security.stackexchange.com/a/59529/8340) - 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. – SilverlightFox Jun 28 '14 at 19:54
  • @SilverlightFox, right... So coming back to the original point: does `Encrypted Token Pattern` offer any **meaningful** protection over `Double Submit Cookies` if attackers who can write cookies can carry out `Session Fixation` attacks? – Gili Jun 29 '14 at 19:24
  • 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. – SilverlightFox Jun 29 '14 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.

Fleche
  • 4,024
  • 1
  • 17
  • 20
  • 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 05 '14 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 05 '14 at 17:13
  • According to http://webstersprodigy.net/2012/08/03/analysis-of-john-wilanders-triple-submit-cookies/ neither Double nor Triple Submit Cookies are safe. I'll keep on looking. – Gili Jun 05 '14 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 05 '14 at 17:37
  • If the attacker can set cookies for the target domain, then all CSRF protection of the log-in form is futile. The attacker would simply authenticate himself and then force this session ID on the user. No need for any CSRF tricks. So in this specific case, yes, both techniques are equally useless. But CSRF attacks are generally used to attack *authenticated* users and take actions on their behalf. If the attacker changes the victim's session ID in an attempt to break the Synchronizer Token Pattern, this defeats the whole purpose of the attack. So the techniques do *not* have the same issues. – Fleche Jun 05 '14 at 18:06
  • Agreed, but you need to edit your answer because it (wrongfully) implies that the Synchronizer Token Pattern is more secure than Double Submit Cookies when you don't control subdomains. It should be noted they are *equally* vulnerable to such attacks. – Gili Jun 05 '14 at 19:42
  • They're *not* equally vulnerable, as I've just explained. When DSC is used, a cookie attack can break the entire CSRF protection. When STP is used, a cookie attack doesn't get you anywhere. Let's say you've just replaced the session cookie of the user. How does that help you with regard to CSRF now? At the very best, you could use the victim as a “proxy” to conceal your IP address when you use your own account. But this is laughable compared to the impact of breaking DSC and being able to use *other* accounts. – Fleche Jun 05 '14 at 20:40
  • 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 http://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 05 '14 at 20:52