CSRF token discussion


ljm42

Recommended Posts

I am glad that unRAID has some CSRF protection built-in. Unfortunately, the token is so long-lived that its value is questionable. The token is generated at boot time and kept until a reboot... my 6.3.5 server has been up 57 days, so the same token has been used the entire time. This is far longer than industry recommendations of generating a new token for every session.

 

The dangers of long-lived tokens are exacerbated by the fact that tokens are used on some query strings as well, where they can show up in log files or referrer headers.

 

So... can we consider adding a cron job to generate a new token on a regular basis? Changing the token once a day at 2am should have minimal impact, although every 3 or 6 hours would be even better.

 

The downside to changing the token at regular intervals is that it might change in between the time a page loads and when you hit submit, thus invalidating a legitimate request.  To get around that the server could track the previous token in addition to the current one, and consider either token valid.

 

The other difficulty is that tokens are needed by javascript that is constantly polling the server to update the interface. Users may leave the dashboard open for days at a time, and expect it to work regardless. Perhaps a variation of this:
  https://github.com/limetech/webgui/pull/95 
could be used to let the javascript access the current token if it is trying to submit an old one.

  • Upvote 1
Link to comment

The csrf must be generated new for every new browser session established at a minimum to have any meaningful security impact. A browser session in Chrome should never use the same CSRF Token as one in IE or Firefox or Edge. The same applies if you're running a second session in the browser.

 

This should be more doable in 6.4 since it has NGIX available, even if it will take some rework/refinement in the pages and javascript.

Link to comment
  • 1 month later...
On 7/23/2017 at 5:14 PM, BRiT said:

The csrf must be generated new for every new browser session established at a minimum to have any meaningful security impact. A browser session in Chrome should never use the same CSRF Token as one in IE or Firefox or Edge. The same applies if you're running a second session in the browser.

 

This should be more doable in 6.4 since it has NGIX available, even if it will take some rework/refinement in the pages and javascript.

 

Can you explain the technical reason for this, or post a link that does?

Link to comment
1 hour ago, limetech said:

 

Can you explain the technical reason for this, or post a link that does?

 

It took me a while to find external means for this, as its been years since I had to implement them, but the following should help you out. When I ran various security scanning software (such as IBMs AppScan or others) at major financial institutions, the tests would explicitly fail if the CSRF Token was the same between different client sessions. Using a GUID for the life of a user's session as CSRF was enough to pass the tests.

 

This is a link from the open software security community. Note the unique per user session characteristic.

 

https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)_Prevention_Cheat_Sheet

 

--------

Synchronizer (CSRF) Tokens

  • Any state changing operation requires a secure random token (e.g., CSRF token) to prevent CSRF attacks
  • Characteristics of a CSRF Token
    • Unique per user session
    • Large random value
    • Generated by a cryptographically secure random number generator
  • The CSRF token is added as a hidden field for forms or within the URL if the state changing operation occurs via a GET
  • The server rejects the requested action if the CSRF token fails validation

In order to facilitate a "transparent but visible" CSRF solution, developers are encouraged to adopt the Synchronizer Token Pattern (http://www.corej2eepatterns.com/Design/PresoDesign.htm). The synchronizer token pattern requires the generating of random "challenge" tokens that are associated with the user's current session. These challenge tokens are then inserted within the HTML forms and links associated with sensitive server-side operations. When the user wishes to invoke these sensitive operations, the HTTP request should include this challenge token. It is then the responsibility of the server application to verify the existence and correctness of this token. By including a challenge token with each request, the developer has a strong control to verify that the user actually intended to submit the desired requests. Inclusion of a required security token in HTTP requests associated with sensitive business functions helps mitigate CSRF attacks as successful exploitation assumes the attacker knows the randomly generated token for the target victim's session. This is analogous to the attacker being able to guess the target victim's session identifier. The following synopsis describes a general approach to incorporate challenge tokens within the request.

  • Upvote 1
Link to comment

Thanks for looking that up and I'm very familiar with that doc but does not explain why they recommend changing the token for every session or not be shared between browsers.  That is, what is the attack vector?  In unRaid case we are guarding against a csrf attack where someone has embedded some malicious javascript that tells the server do do something (like shutdown for example).  But the POST operation to the server needs to include the proper csrf_token value.  How does the attacker know what this token value is (browser same-origin policy protects against script learning this)?  At present we use a 64-bit value which would take javascript a hell of a long time to "guess".  What I thought you were going to point out was that our token was not long enough, which is something I've wondered about but it's real easy to make it longer.

 

One thing I would like you to consider.  By making a blanket statement, "... to have any meaningful security impact " is a little alarmist on your part because you don't show this to be the case.

 

The OP said, "The dangers of long-lived tokens are exacerbated by the fact that tokens are used on some query strings as well, where they can show up in log files or referrer headers."  That is maybe a legit concern if we can think of a specific attack vector.

  • Upvote 1
Link to comment

The general idea of a CSRF token is to have an unguessable string that is generated by the server and submitted as part of any sensitive action.  It is essentially an automated second password, required in addition to the standard authentication, before action can be taken.

 

Unguessable is key, otherwise it adds no value. The main strategy to make it hard to guess/steal is to make it unique and short-lived. If the token expires with the session, then any work the bad guys put in to determine the token is lost when the session closes. That makes it a very tough target for an attack.

 

In our case, a single token is shared across all browsers, all sessions, all users (well, there is really only one "user"), all plugins, and all apps (such as ControlR), until a reboot. 

So clearly at this point we are not relying on uniqueness or a short lifetime to help keep the token secure.  But where a short lifetime would discourage hackers from looking for the token, our multiple-month lifetime would probably do the opposite. Admittedly, I'm having a hard time coming up with a concrete example of how they might take advantage of this, beyond the log files idea. But that doesn't mean there isn't a way!

 

Based on my (limited) understanding of how unRAID works, it seems like it would be difficult to move to a true session-based system that would allow unique tokens. That's why I was suggesting to come up with a way to change the global token on a regular basis. To minimize disruption, the system could accept the previous token and transparently send the current one back to the client.

 

Overall to me it just "feels" wrong to have a global CSRF token that doesn't expire until the server is rebooted. I realize security is done in layers, but this layer feels weak.

  • Like 1
Link to comment

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.