41

Rails automatically adds CSRF protection to all forms by default by adding an authentication_token to all forms generated by the site.

I'd really like my site to have a simple sign up form on the front page of the site, which of course would be a static HTML page. This would ideally avoid hitting the Rails stack at all, allowing me to serve far more requests to the front page.

The downside of this is that it makes CSRF protection more difficult.

But I'm wondering if it is really necessary to have CSRF protection on a sign-up form, considering that CSRF attacks typically depend on the victim being logged in so that trust can be exploited. The sign-up form would log the user in if it validates correctly, but I don't think that would be any use to an attacker.

Is there an established view on this or a work-around using Rails/jQuery?

John H
  • 2,488
  • 1
  • 21
  • 35
  • 1
    possible duplicate of [Do login forms need tokens against CSRF attacks?](http://stackoverflow.com/questions/6412813/do-login-forms-need-tokens-against-csrf-attacks) – thomasrutter Apr 01 '14 at 14:54
  • 2
    *Sigh* It's not a duplicate. Please read the other question, it's about log-in forms. This is about the registration phase. – John H Apr 01 '14 at 16:23
  • 3
    Note that if your sign-up form automatically logs you in after it's been submitted, it is vulnerable to the same class of CSRF attacks as the log-in page http://stackoverflow.com/questions/6412813/do-login-forms-need-tokens-against-csrf-attacks – George Powell Jan 12 '16 at 09:07

6 Answers6

18

On CSRF

First, one has to make clear what CSRF actually is.

Cross site request forgery is a type of malicious exploit of a website whereby unauthorized commands are transmitted from a user that the website trusts.

Consider this following example: A hacker knows that you have an account on www.example.com, and let's say that's a website you have logged into and still have a valid session running. Now the hacker can lure you into opening another website, say trustme.com, on which he has posted an image with the following code:

<img src="http://www.example.com/users/delete"/>

If the programmers of www.example.com actually made it possible to delete your account through that URL with a simple GET request and the hacker knows that, simply viewing and loading that image with your valid cookie will delete your account on example.com, even though you were only surfing trustme.com and it seemed like these two sites had nothing to do with each other.

To summarize this example, CSRF exploits the trust that a site has in a user's browser, in this case the trust that www.example.com had in your browser.

To use that analogy for your case would mean to exploit your site's trust in the user's browser - but that trust hasn't been established yet, because the user has not logged in yet when he sees your form. You have to make sure, though, that the user gets redirected when already logged in and trying to load the page with that form again, because otherwise that established trust can be exploited.

So, as a rule of thumb, whenever you use cookies and sessions for requests to validate a user, i.e. to confirm or establish trust in a user, use CSRF protection. Since you want to establish trust in your user when he signs up, the same applies.

Unfortunately, CSRF attacks are not limited to only that. I found out about two other things that can happen (and it is certainly not limited to that):

1.: The following is a nifty example of spying on your account, made possible by omitted CSRF protection on login forms:

  1. The hacker creates an account on a website you actually trust (youtrustthis.com)
  2. He forges a login request from your browser with his own credentials and tricks you into using his account
  3. If you don't notice that you were actually surfing youtrustthis.com as another user, the attacker will later see what you did "on his behalf", which is pretty much spying on you

2.: Without CSRF protection, a hacker can mimic your login or sign up form in his own html document and conveniently submit it again and again (or just do it using curl from the terminal) without the trusted site noticing that the requests do not actually come from itself - i.e., the actual login form on the trusted domain never having been displayed in your browser and not being submitted from there. This enables him to perform brute force attacks much easier. If the malicious user succeeds in trying to find out the credentials, your server will respond with a valid session cookie and trust that user, by which he steals your identity. If it is a sign up form, he will be able to sign up massive amounts of accounts and thereby spam your database.

To summarize this: Go with CSRF protection. A malicious user can very much use unsecured login and sign up forms to misuse your site and spy on your users or steal their identities.

For more information, also refer to this similar question (for login forms) and this academic paper. The latter has a dedicated chapter on login CSRF on page 3. Also, check out this CSRF prevention cheat sheet.

On potential workarounds

Since CSRF protection uses sessions to compare the token generated on the server-side with the one that was submitted from a form, I cannot think of a way to do this only client side, i.e. without hitting the Rails stack. The whole point is that the client only receives the token after it gets generated server side.

Community
  • 1
  • 1
Dennis Hackethal
  • 13,662
  • 12
  • 66
  • 115
  • 1
    Thanks for this. It's a comprehensive answer, but I'm talking specifically about Sign Up forms, not login forms. I understand login forms MUST be CSRF proof. However, if it doesn't really matter to me if someone creates an account using a fake site/curl etc then is there a problem with not protecting a Sign Up form? Because surely another user can't be compromised this way? – John H Mar 24 '13 at 23:39
  • Generally the answer is: Any form should be CSRF protected. Considering the minimal overhead csrf protection causes, I would really just use it. After signing up, the rails stack has to be loaded anyways. It is your decision, but I would go with it. – Dennis Hackethal Mar 25 '13 at 00:01
  • 1
    Thanks for your answer, it cleared up a lot for me but I have to disagree on your last point. Across my portfolio, not caching front pages would have a huge overhead. The front page simply gets multiples of the traffic any other part of the site gets and is most likely to experience traffic spikes. So for us, if there's no work around for csrf on the signup form it can't go on the front page. – John H Mar 25 '13 at 01:17
  • 5
    I'm going to take the contrary stance and say it's totally fine. Charles' comment smells of "I don't want to think about your case so I'm going to give a blanket response". – 000 Mar 27 '13 at 13:24
  • Not protecting your sign up form could allow an attacker to create an account for you and if you continue to use that account the attacker will have access to that same account. You can help mitigate this by making your sign up form NOT log you in and forcing users to change their password onfirst login, ensuring that login form has CSRF protection. It would be easier on your users to protect the sign up form. There are alternative methods that don't need a token, such as a referrer or origin check: https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)_Prevention_Cheat_Sheet – thomasrutter Jan 22 '14 at 00:31
  • I agree with Joe Frambach, this answer is not relevant to the specific question about CSRF tokens on *sign up* forms. I'm also building a static site with a sign up form, and I want to cache all of the landing page in S3. My login page will be served by the Rails app and include a CSRF token, but I think it's fine to have a sign up form with no CSRF token. My sign up form already requires a valid Recaptcha token and a valid Stripe card token, so I think an additional CSRF token is unnecessary. – ndbroadbent Sep 24 '17 at 12:55
18

No, for this specific situation not. A CSRF attack allows an attacker to exploit the rights that a victim has, e.g. bank.com/pay?ammount=1000&to=34.67.978.246

It makes no sense to attack the log in form, since an attacker can log in by himself if he has the information that is required for a succesfull attack on the login field (the username and password).

The reason why Rails uses CSRF protection on the login field is simple: it's much more simple to implement CSRF protection globally than for 95% of the fields ;)

Ahmad Baktash Hayeri
  • 5,802
  • 4
  • 30
  • 43
f4der
  • 711
  • 4
  • 18
  • 11
    Not true. Google for "login CSRF". An attacker could log you in to or register you for an account they also have access to. Any continued use of that site will be on an account that the attacker also has access to. See also this question: http://stackoverflow.com/questions/6412813/do-login-forms-need-tokens-against-csrf-attacks – thomasrutter Jan 22 '14 at 00:25
  • In some very specific cases this *might* be a risk. The attacker must supply a valid account that looks entirely similar to the account of the user. If you planning this kind of complex attacks, you could also create a page that fetches the CSRF key with AJAX and than submit it. – f4der Mar 31 '14 at 13:28
  • 1
    "you could also create a page that fetches the CSRF key with AJAX and than submit it" - no, this is the scenario that CSRF protection actually prevents. It's not just the token that you need when submitting, it's a token that must correspond to a cookie unique to the user, which the attacker's site is unable to read or write because of same-origin policy. Fetching CSRF key with AJAX and submitting it *from another site* would not be possible if there is CSRF prevention. – thomasrutter Apr 01 '14 at 14:46
  • 4
    It frustrates me that this is still the accepted answer; that CSRF protection is supposedly "not needed" for signup forms - this is untrue. CSRF protection doesn't just prevent unauthorised actions un behalf of an established user account but also (often dubbed "login CSRF") prevents the unauthorised interception of a user's sign-up process by an attacker who tricks the user into signing up under an account the attacker created in the user's name and continues to have access to, which will have long-term security ramifications if the user continues to use that account. – thomasrutter Apr 01 '14 at 14:58
3

It seems to me that there is little technical reason to be concerned about csrf from a sign-up form. Attacker could trick someone into creating a new account on your site - if the victim then used your site, the attacker could spy on their actions since he would also have access to the account?

The more likely risk is probably non-technical. When your site gets a security audit, you'll have to explain why csrf isn't a risk here... and proving a negative is difficult... "Appscan has flagged this as a critical security hole - why don't you fix it? Why can't you have a nice clean report like Charles?" :)

ss ulrey
  • 298
  • 1
  • 8
2

If you want to cache the front page but still have CSRF protection (which is probably a good idea, as Charles said) you could inject the appropriate authenticity token via Javascript once the page has loaded.

There's some info about this at http://broadcastingadam.com/2011/05/advanced_caching_in_rails/ under the "CSRF and form_authenticty_token" header. The relevant code is:

$("meta[name='csrf-token']").attr('content', '<% Rack::Utils.escape_html(request_forgery_protection_token) %>');
$("meta[name='csrf-param']").attr('content', '<% Rack::Utils.escape_html(form_authenticity_token) %>');

With this technique, you can cache your entire homepage, at the cost of all clients making an additional (but very small, and quick) request to get this auth token.

Alex Ghiculescu
  • 7,522
  • 3
  • 25
  • 41
  • 1
    This would indeed work, though you would definitely lose the load reduction that you would have got through caching. Now instead of one dynamically rendered page with a token, you're replacing it with one call for a cached static page plus one call for a dynamically rendered page containing the token which is passed to Javascript. – thomasrutter Jan 22 '14 at 11:06
0

Generically speaking its a good idea to protect your registration forms against CSRF attacks. Consider Google Search, and suppose the login form is protected against CSRF but the registration form is vulnerable. An attacker can force a victim to register a new account with credentials the attacker knows, and from that moment on any search the victim does will also be visible to the attacker, because he knows the credentials to log in the victims account. This assumes the vulnerable site immediately logs in the user after registration.

Other scenario, with email providers, is to create accounts for spam purposes. An attacker can force victims to create new accounts, with a CSRF in the registration form, and use those accounts to send spam. The idea is to defeat security mechanisms that throttle account creation based on IP or country.

However, in a specific scenario, it might not possible to exploit a vulnerable registration form, but this kind of analysis might be hard for a non-expert in the subject. Its a good idea to protect the form, but there aren't many scenarios where a successful attack can be create thus the risk is normally low.

tmendo
  • 9
  • 4
0

Yes, So other websites can't mimic your sign-up form! As simple as that.

What can they achieve by doing it?

  • First: you don't wanna allow that. you wanna own where requests come from.
  • Second: False alerts can be blocked.
  • Third: If you allow auto login post sign up it's as vulnerable as login form csrf
mayankcpdixit
  • 2,456
  • 22
  • 23