CSRF in Go Web Applications - security

I want to implement CSRF prevention in my Go web application. Users don't log in, but they do fill out forms and pay (via Stripe Checkout).
Posting something sets a key in a session variable (cookie) so they can later edit what they've posted, and a URL in an email allows them to come back when the cookie has expired and edit it again if need be.
From what I can see, I can use https://code.google.com/p/xsrftoken/ with the "double submitted cookie" method to implement CSRF prevention by:
Generate a CSRF token against an arbitrary user ID (uuid.V4() via go-uuid), like so:
if session.Values["id"] == "" {
session.Values["id"] = uuid.NewV4()
}
csrfToken := xsrftoken.Generate(csrfKey, session.Values["id"], "/listing/new/post")
... and store that in the session and render it in a hidden field in the template:
session.Values["csrfToken"] = csrfToken
...
<input type="hidden" id="_csrf" value={{ .csrfToken }}>
When the user submits the form, I need to get the ID I generated, confirm that the submitted csrfToken from the form matches the one in the session, and if so, validate it with the xsrf package to confirm it hasn't expired:
userID := session.Values["id"]
if session.Values["csrfToken"] != r.PostFormValue("csrfToken") {
http.Redirect(w, r, "/listing/new", 400)
}
if !xsrftoken.Valid(session.Values["csrfToken"], csrfKey, userID, "/listing/new/post") {
http.Redirect(w, r, "/listing/new", 400)
}
My pertinent questions are:
Should I generate a new token every time the form is rendered? Or is it acceptable to re-use a non-expired token for a single user session? Update: According to this answer I should only generate a new token per session (i.e. so the same user gets the same token on the same form, until the token expires)
Given the updated question, how do I handle the situation where a created token expires between the time the user requests the form and then submits the form? (perhaps it had 10 minutes left, and they alt+tabbed out for a while) Re-direct them back to the form (re-populated, of course!) and generate a new session id + csrf token?
Is there a different way to do this? Coding Horror indicates that SO generates a unique key for every HTML form sent to the client? How would I go about going down this route with the xsrf package, given that it wants a userID when generating a new key?
What else have I overlooked?

Should I generate a new token every time the form is rendered? Or is
it acceptable to re-use a non-expired token for a single user session?
Update: According to this answer I should only generate a new token
per session (i.e. so the same user gets the same token on the same
form, until the token expires)
It is a good idea to regenerate both the token and session ID often. Given a persistent attacker and a viable entry vector, it's just a matter of time until the attacker obtains both. If, however, at least one of both identifiers regenerates before the attacker is able to crack the current one, then no problem.
Given the updated question, how do I handle the situation where a
created token expires between the time the user requests the form and
then submits the form? (perhaps it had 10 minutes left, and they
alt+tabbed out for a while) Re-direct them back to the form
(re-populated, of course!) and generate a new session id + csrf token?
You can update cookies and CSRF tokens through AJAX if you want to give your client vast time to fill out a form.
Is there a different way to do this? Coding Horror indicates that SO
generates a unique key for every HTML form sent to the client? How
would I go about going down this route with the xsrf package, given
that it wants a userID when generating a new key?
The more tightly bound a token is to a certain action that requires authentication, the more fine-grained control you have. If you can uniquely identify each form in your application then I'd say do it.

I've created a CSRF protection package for Go called nosurf. Here's how it handles the areas you mentioned:
Token is created by taking bytes from CS PRNG and encoding them using base64. It is not regenerated for every page load or every form, though there is a user-callable function for regenerating the token.
It is then stored in a cookie (not a session, as it's a generic middleware not intended for any specific framework only). The cookie lasts one year, but you can easily modify this duration.
nosurf takes care of cancelling the request and either returning 403 or calling your custom failure handler (if set). You don't have to have if CsrfCheckOk(r) { ... } or anything like that in your code.
Sadly, it doesn't address token expiring inbetween the page load and the form submission.
So that's it, even though I'm not sure it is the best way to handle CSRF all-around. A package for a specific framework might handle it better in some ways due to tight integration.

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.

How to send the CSRF token to the client when using synchronizer token pattern?

In the synchronizer token pattern, the server generates a random token and this token has to be submitted by each form submission by the client. How can the client get to know the CSRF token that was created in the server?
Upon GET requests, you can put the token into the resulting page. It can either be written in forms as a hidden field to have it sent automatically when a form is sent, or in something like a meta header (<meta name="csrftoken" content="...">), or pretty much any other way.
If it's just plain old form posts, a hidden field is probably the easiest. If javascript is involved (ajax requests), you will probably be better off with one central location in the page (like a meta header) where any javascript can take it from.
Also with forms, you can generate a different token for each new page download, but for ajax-heavy applications changing the token will lead to problems - for most applications, one token per login session is acceptable.

How should I store a token generated by a RESTful API?

I have built an API that generates an authentication token for the users that log in. At this time I also have a client application written in Node.JS.
When I make the request with the user credentials from the client application to the API I get the authentication token: how should I store it in the client application? I'm not supposed to request a token every time I want to make a request for the API, correct?
I thought about putting the token in a Cookie, but I don't think that's the best solution.
What would you recommend?
Upon successful login, a unique, one-use token should be created server side and stored in the database against a user id and timestamp. You store the token in a cookie client-side. You then pass the token up to every subsequent API call. The server should then check the token is valid (ie not expired, say issued or update less then say 30 minutes ago). If it is valid, you can retrieve the user details stored against that token and perform whatever backend functionality you need (as the user is authenticated). You then update the timestamp for that token (refresh the session as you want the login to time out after say 30 minutes of no user interaction). If a token is expired or non-existent when you get the API call, redirect to the login page.
Also, you probably know this already, but make sure the token is unique and non-guessable, I tend to generate new random GUIDs and encrypt them, do not use sequentail ids or anything like that.
I think that this link could help you:
Implementing authentication with tokens for restful applications - https://templth.wordpress.com/2015/01/05/implementing-authentication-with-tokens-for-restful-applications/
In fact, you should have a token with an expiration date, so you don't have to get a new token each time before sending a request. When the token expires, you simply need to get a new one from a service "refresh token".
Regarding the question about how to store the token in the client application, I think that you could keep it in memory (map or embedded database).
Otherwise to finish, I don't think that it's a good idea to use cookies in such use case.
Hope it will help you.
Thierry
We're working on an application that uses a very similar approach. The client application is a static HTML5/JS single-page application (with no server-side generation whatsoever) and communicates with an API server.
The best approach is to store the session token in memory: that is, inside a variable in the JS code. If your client application is a single page, it shouldn't be a problem.
In addition to that, we also keep the session token in sessionStorage to preserve it in case the user refreshes the page. To preserve the token when new tabs are created (sessionStorage is specific to a browser window), we also store it in localStorage when the page is being closed, together with a counter for open tabs (when all tabs of the application are closed, we remove the token.
// Handle page reloads using sessionStorage
var sess = sessionStorage.getItem('session-token')
if(sess && sess !== 'null') { // Sometimes empty values are a string "null"
localStorage.setItem('session-token', sess)
}
// Set a counter to check when all pages/tabs of the application are closed
var counter = parseInt(localStorage.getItem('session-counter') || 0, 10)
counter++
localStorage.setItem('session-counter', counter)
// Event fired when the page/tab is closing
window.onbeforeunload = function() {
var counter = parseInt(localStorage.getItem('session-counter') || 0, 10)
counter--
localStorage.setItem('session-counter', counter)
// All pages are closed: remove the session token
if(counter <= 0) {
// Handle page reloads using sessionStorage
sessionStorage.setItem('session-token', localStorage.getItem('session-token'))
localStorage.removeItem('session-token')
}
}
For more information about localStorage and sessionStorage: https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API
Why not cookies? Cookies are bad for two reasons:
1. They are generally more persistent, being shared across browser windows and tabs, and they can persist even after the browser is closed.
2. Most importantly, however, by the HTTP specifications they must be sent to the web server every time a request is made. If you're designing an application where the client is completely separated from the API server, you don't want the client's server to see (or log!) the session token in any case.
Some extra advices:
Session tokens must expire. You can achieve that by storing session tokens in the database on the server and verifying them on every request and/or "signing" them (adding a timestamp to the token in plain text, then adding a signed part, for example a HMAC hash, with the timestamp encoded with a secret key you only know).
Tokens can be reused as many times during their life. However, after a certain number of seconds you may want your server to refresh the tokens, invalidating the old one and sending a new token to the client.

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.

Securing POST data in web application

I have a web application which has basic authentication - username, password, session and stuff. However I have a specific need to prevent users from spoofing the POST requests (even for logged in users). In my application, I am specifically validating the user's session before accepting the POST data (taking care of XSS and stuff also).
Like:
if(user session exists)
{
// handle the data POSTed
}
else {
// ...
}
I am storing the sessions IDs in the database. Is there anything else I should be aware of to prevent bogus POST requests or is this sufficient?
I am specifically validating the user's session before accepting the POST
If you mean what is normally meant by ‘session’: a persistent token stored in a cookie that identifies the user and associated session data, then no, that's not enough. That cookie is sent automatically by the browser even if the POST request was provoked by another (attacker) site.
The keyword you are looking for here is Cross-Site Request Forgery or XSRF, where an authenticated user can be made by an attacker (via scripting or other methods) to make a GET or POST request to your site. Such requests are not generally distinguishable from legitimate requests. (Some people try to do so though checking the HTTP referrer data, but this is unreliable.)
These attacks are not quite as immediately damaging as server-side (SQL, command) or client-side (HTML, JavaScript) injections, but they are more common than both: few web programmers both to include the proper countermeasures, unfortunately. Until they get their sites compromised by an XSRF hole anyway.
There are various way to defend against XSRF, but the only really effective approach is to include in each submittable form a secret value that the third-party attacker won't know. This is often known as a post key, as mentioned by Eimantas.
There are various ways to generate such secret information. A simple approach is to add a randomly-generated code to each user's account details, then put that in a hidden field in the form and check for its presence in the submission. eg in PHP:
<form method="post" action="delete.php"><div>
<input type="hidden" name="key" value="<?php echo(htmlspecialchars($user['key'])); ?>"/>
<input type="submit" value="Delete" />
</div></form>
if ($_POST['key']!=$user['key'])
// error
An attacker won't know the key for that user so can't make a link/form that contains it.
You could also use a cryptographic hash function on the user's ID with a server-secret key, rather than keeping a separate code. With a hash, you can also throw in other stuff like an expiry time so that forms have to be submitted within a certain timeframe. Or you can generate a one-use transaction key, which you can also use to make sure you can't submit the same form twice (for stopping double-posting).
You could try generating post keys for each post request. Sort of additional param that shows that post request is valid and was executed from a form on your page.
If you are building valid POST requests in Javascript in the user's browser, there is not much you can do to prevent a determined user from submitting bogus POSTs to your server. The user has a valid session id that he can use to make a POST request. He also has access to all of the code and all the other data that code has access to for building the request.
You can't rely on browser-side code to secure your system. The security has to be enforced at the server. For example, all operations on objects should be authenticated and authorized.
Use a CAPTCHA image.
The web is built on REST, which by definition is all about transferring state from one point to another. Someone with enough time on their hands could craft a POST request that emulates an active session.
Like all secure requests, CAPTCHA is validated server-side.
In my current application I have some code which is sent to the browser and the browser then posts back and must not be able to modify it. What I do is to append a secret string to the value, get the SHA1 checksum of that full string, and then require the browser to send back both the value and the checksum. I'm pretty sure this is how .NET does viewstate, too.
If user session is long-lived, you are still susceptible to XSRF. You need to take measures against that too.
If you are on .NET, check out AntiForgeryToken,
http://msdn.microsoft.com/en-us/library/dd492767.aspx
When accepting user input, the zero-level thing you need to do, before storing things in the database is to make sure you run the data via the mysql_real_escape_string($MyPostData) function.
Also, it is good for every variable/data you want to accept via POST to validate it programmatically based on its type and what you intend to do with it.
These are two main rules for making sure there's no 'funny' business coming from the user: making sure you work with valid variables AND making sure data that gets to the database is verified and escaped properly.
With your model (and especially if you use integer numbers for your session IDs) an attacker can easily submit a request on behalf of another user (e.g. decrement your own session ID and you are already someone else provided this session ID exists).
You need to have a unique session key/guid associated with each session ID and stored both in the DB and on the client in the cookies. Each time your client submits a request you should read not only session ID but also the session GUID and then validate them both against your database values.
In addition to that you may also want to consider some XSRF mitigation strategies.

Resources