CSRF protection: do we have to generate a token for every form? - security

Do we have to generate a token, for every form in a website? I mean, every-time to generate different token for every requested form? If not, why?

In general, it suffices to have just one token per session, a so called per-session token:
In general, developers need only generate this token once for the current session. After initial generation of this token, the value is stored in the session and is utilized for each subsequent request until the session expires.
If you want to further enhance the security, you can use one token per each form/URL (per-form token) to mitigate the impact when one token leaks (e. g. XSS) as an attacker would only be able to successfully attack that specific form/URL.
But using per-request tokens, i. e. tokens that change with each request, rather cuts the usability of the website as it restricts parallel browsing:
To further enhance the security of this proposed design, consider randomizing the CSRF token […] for each request. Implementing this approach results in the generation of per-request tokens as opposed to per-session tokens. Note, however, that this may result in usability concerns. For example, the "Back" button browser capability is often hindered as the previous page may contain a token that is no longer valid. Interaction with this previous page will result in a CSRF false positive security event at the server.
So I recommend you to use either per-session tokens or per-form tokens.

No, you just need to generate a token on a per-session basis.
Tokens are very unlikely to be leaked accidentally by users and generating a token per form makes things very complicated if a user is browsing the site in two different tabs/windows at once.

Related

Securely renewing a session without javascript and without breaking CSRF protection

I am working on doing some security hardening on a legacy web application, and have run into a bit of a conflict.
So, I added CSRF protection to the application with a CSRF token as a hidden input in forms. Pretty normal.
Then I dramatically lowered the session timeout (the previous value was 8 hours, which obviously is unacceptable from a security point of view). However, to prevent users from losing their work when their session times out, I also implemented a modal login dialog with some JavaScript to renew their session before completing the form submission. This JavaScript also updates the CSRF token input with the new value from the server upon a successful login, as obviously the old CSRF token was associated with their previous now-expired session. Losing work is a huge deal for this application because users will genuinely spend a hour on a single page, just filling out data in a form and never hitting the save button, all the while the server doesn't know that the users are doing anything.
However, there is a not-insignificant portion of our userbase on machines with some pretty draconian policies forbidding JavaScript entirely. So, a secondary workaround is also needed for these people. If I were building the application from scratch, I feel the best solution for these users would be to simply re-populate all the inputs on the page they were on (prior to the timeout) with values from the POST data (after the user logs back in). However, implementing that would be such a gargantuan undertaking in this old code that it may as well be impossible.
We really had a hard time coming up with a workable solution for the non-JavaScript users. The best I've been able to come up with is to place a fixed link in the corner of the screen informing the user of when their session would expire, and redirecting them to the login page in a new tab if they click the link. That way, they can click the link and log in again before submitting the form. However, that breaks the CSRF protection, as upon returning to the form the CSRF token in the hidden input no longer matches the one in new session.
Short of refactoring literally thousands for forms, is there any way I can keep users without JavaScript from losing work when their session expires, without breaking CSRF protection?
Theory
If the CSRF token is not associated with a specific session, how does one prevent an attacker from obtaining their own CSRF token by visiting a page in the application, ...
One does not attempt to prevent an attacker from obtaining their own CSRF token. CSRF protection does not rely on attacker's inability to obtain and submit a valid CSRF token. CSRF protection depends on two CSRF tokens and relies on attacker's inability to obtain and submit back to the server two tokens that are related to each other. In practice, "related to each other" means "cryptographically bound to each other".
An attacker can obtain a valid CSRF token and maybe could even additionally obtain the second CSRF token which is also valid on its own. However the attacker won't be able to ensure both tokens are cryptographically bound to each other.
Implementation
There are many protection schemes. For example, looking at the high level like this:
The server creates two CSRF tokens and sends both to the client along with the session cookie. The first CSRF token is sent as a cookie (let's call it 'form cookie'), the second one is sent as the hidden form input you are currently using.
The server has a symmetric key that is never sent out, let's call it 'server key'. To create a form cookie, the server generates a random sequence of bytes (let's call it 'CSRF_key') and encrypts it using the server key. The encrypted output, serialised as a string, is sent to the client in the form cookie.
The server creates a string by concatenating the current timestamp and a GUID: timestamp+GUID. It then calculates a hash of that string using HMAC algorithm: HMAC(timestamp+GUID, CSRF_key). HMAC requires a key as the second argument and the server uses CSRF_key generated at the previous step as the HMAC key. The HMAC output is serialised as a string and concatenated with the timestamp+GUID string. The concatenation is sent out as the second CSRF cookie e.g. your hidden form input.
When the server gets POST with the form, it gets both CSRF tokens (one as a form cookie, another as an hidden input). It first checks the session, then it verifies that the timestamp (taken from the timestamp+GUID string) is valid e.g not too stale, not in the future etc. Then the server uses the server key to decrypt the form cookie and get the CSRF_key.
The next step: Calculate HMAC of the timestamp+GUID string using CSRF_key as the HMAC key. Compare the output with HMAC value in the hidden field. If identical, then CSRF check is ok so accept the form and generate another CSRF_key to be used as the 'form cookie' for the next form.
Note: In many real life scenarious the implementation is an overkill and could be simplified. Also it's a high level blueprint, there are important low level implementation details like sufficient keys length, proper cookie attributes etc.

Confusing about CSRF protection strategies

I am testing a web application. CSRF is applied and sent in cookies and header but not in the form as hidden input. The csrf token does not change for every request but it change during the session. How often should the csrf token change ? Should it change per session or per request ? should the client or the server set the csrf token ? what is the best strategy to apply csrf protection? double submit cookie ? Triple Submit Cookie ? or any other new strategy ?
I'm just going to attempt to answer your questions one by one here.
How often should the CSRF token change?
You can change your CSRF token once per session. Changing it once per request offers no real security advantage and if anything, only serves as an easy way to waste resources and limit usability. For example, a user will not be able to hit the "back" button because they will have an outdated CSRF token, or if they try to resubmit a form with new values (such as after a validation error) it may not send.
Should it change per session or per request?
As discussed, it should change per session. The only time that a user should be given a new token per request is at login. This is to prevent a session fixation attack leading to a CSRF attack possibility.
For example: An attacker accesses the site and generates a new session. They take the session ID and inject it into a victim's browser (eg via writing cookie from a vulnerable neighbour domain, or using another vulnerability like jsessionid URLs), and also inject the CSRF token into a form in the victim's browser. They wait for the victim to log in with that form, and then use another form post to get the victim to perform an action with the still-live CSRF token.
To prevent this, invalidate the CSRF token and issue a new one in the places (like login) that you're already doing the same to the session ID to prevent session fixation attacks.
Should the client or the server set the CSRF token?
The server - always on the server! You want to generate the token from a trusted source, as per OWASP guidelines. This ensures that you know exactly where the token is generated and limits attack surface since an attacker cannot control what happens on the server.
What is the best strategy to apply CSRF protection?
I think CSRF is a very in-depth topic and can't really be summed up in just a few words. This is where a little research and reading can go a long way. I would recommend you take a look at the OWASP CSRF Prevention Cheat Sheet.

Endless session: any security risk?

A legacy app I'm working on let the user fill in a ton of questions and save the answers in a batch at the very end of the questionnaire. The process is lengthy and a typical user may go through a timeout at some point.
The team has come up with the idea of an endless session to bypass that problem. After some Googling I found out many articles explaining how to increase the timeout; however I didn't come across articles exposing the risk of such practice. At first sight I find reasonable to set a timeout.
My questions are:
Do you think that an endless session may open up a security risk?
If so what are the typical risks incurred by that practice?
The main risk is that the session identifier effectively becomes the password if it never expires. Anyone with access to the session identifier could record this offline, and then use this at a later time to login to the application. For example, somebody could copy the session token from the cookie with brief access to a user's machine.
A mitigation for this is to routinely rotate session identifiers. Maybe you could have an AJAX request that fires off every 10 minutes and gets a new token for the current session - even with standard session expiration times (e.g. 10-20 minutes), this would be enough to keep the session alive so that it does not time-out before the form is submitted.
Brute forcing is not an issue: As long as the session identifier has enough entropy, then there is very little risk of this being brute forced. OWASP guidance here on selecting a strong method for session identifier generation.
More on the performance side than security side is that if you're storing objects in memory for each session, then eventually memory will fill as the number of sessions increase.
Another risk with long sessions is that any CSRF or XSS vulnerabilities have a long exposure time for exploitation. A short session timeout would mitigate any attack if the user visited a malicious site targeting your app, because the user would not be authenticated. Even with persistent login, this would be mitigated if you had a long term "refresh token" with a short term (i.e. session) "access token" if your site was sufficiently locked down (e.g. it only allows a request with CSRF protection itself to exchange a refresh token for an access token).
For example if there was an CSRF vulnerability:
[User] --> [Attacker's Site] --> [Your site]
Browser --> Malicious Page builds form for your site --> Submits form via AJAX
With an endless session timeout, this attack will succeed if the user has ever visited your site with their browser.
However if you had two session tokens: A refresh token and an access token and you required an access token to submit the form, this would prevent the attack. As the access token can only be retrieved by a same-site request, making sure that the handler for this request is sufficiently protected against CSRF would mitigate other vulnerabilities that may be present on your site.
Therefore if you must make the session infinite, use a different token that must be exchanged in order to authenticate with your website.
See this post for how to implement "remember me" functionality (aka our refresh token). The drawback is that you must implement the refresh token to access token logic yourself and require that the user must re-send any requests again with the access token (which can be implemented using client-side logic with JavaScript).
The main reason sessions have a time out is to being able to delete any server-side stored data associated to the session at some point. Otherwise your session storage would just always grow and you would never be able to remove any of that stored data at some point.
Granted, the longer a session lasts, the more likely an attacker may be able to guess a session’s ID and possibly hijack it. But that can easily be mitigated by changing the session’s ID now and then.
Endless sessions are not inherently less secure than your session implementation, but it does allow an attacker more time to exploit. For example, with an endless session, session hijacking becomes a little easier, as the attacker has unlimited time. It would also allow for brute-forcing of sessions, but given a sufficiently complexly generated session token, that shouldn't be an issue either.
Basically, it can/will make existing vulnerabilities easier to exploit, but will not weaken the implementation itself.

Why does Express/Connect generate new CSRF token on each request?

As far as I understand there are two approaches in protecting from CSRF attacks: 1) token per session, and 2) token per request
1) In the first case CSRF token is being generated only once when the user's session is initialized. So there is only one valid token for the user at once.
2) In the second case new CSRF token is being generated on each request and after that an old one becomes invalid.
It makes harder to exploit the vunerability because even if attacker steals a token (via XSS) it expires when the user goes to the next page.
But on the other hand this approach makes webapp less usable. Here is a good quotation from security.stackexchange.com:
For example if they hit the 'back' button and submit the form with new values, the submission will fail, and likely greet them with some hostile error message. If they try to open a resource in a second tab, they'll find the session randomly breaks in one or both tabs
When analizing Node.js Express framework (which is based on Connect) I noticed that a new CSRF token is generated on each request,
but an old one doesn't become invalid.
My question is: what is the reason to provide new CSRF token on each request and not to make invalid an old one?
Why not just generate a single token per session?
Thank you and sorry for my English!
CSRF tokens are nonces. They are supposed to be used only once (or safely after a long time). They are used to identify and authorize requests. Let us consider the two approaches to prevent CSRF:
Single token fixed per session: The drawback with this is that the client can pass its token to others. This may not be due to sniffing or man-in-the-middle or some security lapse. This is betrayal on user's part. Multiple clients can use the same token. Sadly nothing can be done about it.
Dynamic token: token is updated every time any interaction happens between server and client or whenever timeout occurs. It prevents use of older tokens and simultaneous use from multiple clients.
The drawback of the dynamic token is that it restricts going back and continuing from there. In some cases it could be desirable, like if implementing shopping cart, reload is must to check if in stock. CSRF will prevent resending the sent form or repeat buy/sell.
A fine-grained control would be better. For the scenario you mention you can do without CSRF validation. Then don't use CSRF for that particular page. In other words handle the CSRF (or its exceptions) per route.
Update
I can only think of two reasons why single dynamic token is better than multiple:
Multiple tokens are indeed better but have at least one dynamic token like one above. This means designing a detailed workflow which may become complex. For example see here :
https://developers.google.com/accounts/docs/OAuth2
https://dev.twitter.com/docs/auth/implementing-sign-twitter
https://developers.facebook.com/docs/facebook-login/access-tokens/
These are tokens to access their API (form submission etc.) not just login. Each one implements them differently. Not worth doing unless have good use case. Your webpages will use it heavily. Not to mention form submission is not simple now.
Dynamic single token is the easiest, and the readily available in library. So can use it on the go.
Advantages of multiple tokens:
Can implement transactions. You can have ordering between requests.
Can fallback from timeout and authentication errors (you must handle them now).
Secure! More robust than single tokens. Can detect token misuse, blacklist user.
By the way if you want to use multiple tokens you have OAuth2 libraries now.

Why not use session ID as XSRF token?

Why does Play Framework use [a signed version of the session id] as Cross Site Request Forgery (XSRF/CSRF) prevention token, rather than the session ID itself?
(With XSRF prevention token, I mean a magic value that must be included in a form submission, for the webapp to accept the form.)
If there's an eavesdropper s/he'll find both the XSRF token and the SID cookie anyway (?).
If there's an XSS exploit, then the malicious JavaScript code can read both the XSRF token and the SID cookie (?).
However:
An attacker cannot construct a valid XSRF token, given a SID, since s/he doesn't have the secret key used when signing the SID to obtain the XSRF token. -- But how could it happen that an attacker gets hold of only the SID, not the XSRF token? Is that far-fetched?
If the SID is sent in a HTTP Only cookie, then an attacker wouldn't have the SID even if s/he found the XSRF token, and perhaps the attacker really needs the SID? -- Is this far-fetched?
Code snippets:
Here Play constructs it's XSRF token (getId returns the session ID):
(play/framework/src/play/mvc/Scope.java)
public String getAuthenticityToken() {
return Crypto.sign(getId());
}
Here Play checks that a <form> has a valid XSRF token:
(play/framework/src/play/mvc/Controller.java)
protected static void checkAuthenticity() {
if(Scope.Params.current().get("authenticityToken") == null ||
!Scope.Params.current().get("authenticityToken").equals(
Scope.Session.current().getAuthenticityToken())) {
forbidden("Bad authenticity token");
}
}
Update:
Play has changed the way it generates XSRF tokens, now the SID is no longer used, instead a random value is signed and used! (I just updated my Play Framework Git repo clone from old Play version 1.1 to new 1.2. Perhaps I should have done this ... yesterday, hmm.)
public String getAuthenticityToken() {
if (!data.containsKey(AT_KEY)) {
data.put(AT_KEY, Crypto.sign(UUID.randomUUID().toString()));
}
return data.get(AT_KEY);
}
Well, then why did they do this change?
I found the commit:
[#669] Fix again and apply for Flash and Errors as well
d6e5dc50ea11fa7ef626cbdf01631595cbdda54c
From issue #669:
create session only when absolute necessary
A session cookie is created on every request of a resource. play should only create a session cookie if there is really data to be stored in the session.
So they're using a random value, not the SID, because the SID might not yet have been created. Well that's a reason not to use a derivative of the SID as XSRF token. But doesn't clarify why they signed/hashed the SID, in the past, when they were using it.
The first thing to say is that you can reuse the session ID as the CSRF token, insofar as it will protect you fine against CSRF and does not automatically create any serious security holes. However, for somewhat sound reasons, OWASP used to explicitly recommend against it. (They now don't address the question at all.)
The argument against reusing the session ID as the CSRF token can be summarized as follows (key points in bold, with justification beneath):
The session ID being acquired by an attacker is generally a more serious security breach than the CSRF token being acquired by an attacker.
All that an attacker gains from having the CSRF token (assuming that some other secure piece of information, like the session ID, hasn't been reused as the CSRF token) is the ability to perform CSRF attacks. This gives them two huge limitations that they wouldn't have if they actually acquired a session ID:
They still need to lure the user with the corresponding session token to an attack page (or have them read an attack email, or view an attack ad in an iframe, etc.) to exploit the CSRF token in any way at all. With the session ID, they'd just need to put it in their browser and then use the website as if they were that user.
While they can send requests using the user's credentials, the Same Origin Policy still prevents them from viewing the responses to those requests. This may (or may not, depending on the structure of the API you're protecting and the attacker's ingenuity) mean in practice that while the attacker can perform actions on the user's behalf, they cannot acquire sensitive information that the user is authorized to view. (Which of these you care more about depends upon the context - one assumes that an attacker would tend to prefer taking the contents of your bank account to merely knowing how much that is, but that they'd also rather know your medical history than vandalise it.)
The CSRF token is potentially easier for an attacker to acquire than the session ID
XSS attacks are likely to permit an attacker to acquire the CSRF token, since it's common practice to bake it into the DOM (e.g. as the value of an <input> element in a <form>. Session cookies, on the other hand, can be kept secret even in the face of a successful XSS attack using the HttpOnly flag, demanding more up-front work from an attacker to usefully exploit an XSS vulnerability.
If the CSRF token is being sent back to the server as a request parameter rather than a custom HTTP header (guaranteed to be the case when including it in ordinary HTML <form> submits), then web server access logs will generally log the CSRF token on GET requests (as it's part of the URL). Thus an attacker who manages to view the access log would be able to acquire many CSRF tokens.
Pages or scripts that the CSRF token is baked into may be cached in the user's browser, permitting an attacker to retrieve them from the cache (conceivably relevant after the user has, for example, used a public machine in a library or internet cafe, and then either cleared their cookies but not their cache, or used a 'Log Out' button that removes their session cookie from the browser without invalidating it server-side).
But if you're reusing the session ID as the CSRF token, then any attack that permits them to acquire the CSRF token automatically gives them the session ID as well.
Therefore you should not reuse the CSRF token as the session ID, since it makes the session ID more vulnerable.
To be honest, I kind of regard everything above as more of a theoretical concern than a practical one. The weak point in the argument is point 2; the only realistic vulnerabilities I can think of that could be used for acquiring CSRF tokens but not for acquiring session cookies are still really serious vulnerabilities. If you have an XSS hole on your site, or an attacker has access to your freaking server logs, chances are you're totally fucked anyway. And in most libraries and internet cafes I've been to, the staff were not security-savvy and it'd be pretty easy to install a keylogger undetected and just harvest passwords - there'd be no need for an attacker to go to the effort of waiting for people to use the machine and then ripping the contents of their browser cache.
However, unless your circumstances somehow make it difficult to store an additional random token for CSRF alongside the random session ID, why not just do it anyway for whatever modest security benefit it gives you?
A pure CSRF attack doesn't have access to the browser's cookies so when you say "eavesdropper", that's only going to be achievable if they're sniffing packets (i.e. no SSL, public wifi).
Depending on the configuration of the Play Framework (I'm not familiar with it so take this as general web app advice), the session and authentication cookies will almost certainly be flagged as HttpOnly so they they're unable to be read from the client via XSS.
Ultimately, the idea of using the synchroniser token pattern to protect against XSRF is to use a unique value (preferably cryptographically strong), known only to the server and the client and unique to that session. Based on this goal, Play Framework seems to do just fine.
Perhaps Play Framework doesn't want the SID in the HTML. An end user, Bob, might download a Web page, and if there's a <form> in that Web page, the SID would be included in the downloaded HTML (if the SID itself is used as XSRF token). If Bob then emails his downloaded page to Mallory, then Mallory would find the SID and could impersonate Bob!?
(Another minor reason not to use the SID: As I mentioned in my update, the SID might simply not be available. Perhaps it's generated as late as possible, to save CPU resources.)

Resources