Persistent cookie normal timeout behaviour - security

Im implementing a persistent cookie based on http://jaspan.com/improved_persistent_login_cookie_best_practice.
Question :
If a user tries to access a page. After the authentication is successful, the used token is removed from the database. A new token is generated, stored in database with the username and the same series identifier, and a new login cookie containing all three is issued to the user.
When you generate a new cookie here, you need a cookie age, I put it as default of 1 month. So, every time the new cookie is generated, should I just put it as default(1 month) or should I store a field in my db which counts the expiry time(something like 1 month countdown). Whats the normal behaviour here ?
Another question, I feel that it is a bit overkill to remove the token and gerenate a new token to db everytime you visit a page. Is this operation as costly as I thought?

Add the expiry both server and client-side, otherwise a cookie grabbed by an attacker would be valid forever.
Changing the token is good and can help protect against the above scenario. Every page visit seems a bit excessive, and could have a performance impact if your site gets busy. How about refreshing it every 5 minutes or so?

Related

Where jsonwebtoken stored in server nodejs . How to expire JWT once user gets logout

I am storing Tokens on Session/Local storage on the client side.The problem I am facing is once a user copies that token and uses it for other logged-in session services it works but it should return invalid token on JWT.varify.
Is there any way to Blacklist/Delete/Expire currently used token once a user has logged out?
There a a few ways to set up a blacklist for that purpose:
1) (Blacklist users in the database) Add a database column isTokenExpired for users and set it to false on a successful login, and true when you want to expire the token (for example when the user changes their password, logs out, or enough time has expired).
The above method will achieve your purpose, but I feel it is an insult to programming. I assume you are using JWT so that the user doesn't have to log in every time, and that you have only 1 server which is doing the authentication and all other server functions. Although JWT was not designed for "sessions", using JWT for this purpose can take load off the database. But if you are then setting and checking another database flag on every user action, you are adding that load again, and you still have all the load associated with the JWT etc, so you might as well just re-auth on every user action.
2) (Blacklist a user/the token in server RAM) When I researched this problem for myself (how to invalidate individual tokens), I found some solutions where the server maintains either a whitelist or blacklist in RAM, so without adding database or file load. This may be a somewhat better solution, but I can't remember the names of any of the libraries that facilitate this. Maybe someone else can mention some of them.
3) Set token to a very short expiry time (For example 60 seconds or 5 minutes) and set up the client to automatically request a new token every (~55 seconds or ~4 minutes 50 seconds). The server would then check and validate the token in the same way I assume you are doing it now, without accessing the database, and would then generate a new token with the same values for all the other fields, but with a new "expiry time" value, and send that token back to the client where it would replace its JWT with this new JWT, and re-start its 5-minute timer. This is a good balance between the other choices, and maintains some of the benefits of using the JWT, but does add some small cost. I think this is a pretty good solution for many applications, but it definitely depends on the specific application, but it is somewhat hacky and definitely not "the right way" to do it.
4) Use JWT + Sessions This is "the right way" to do it. After all my research a long time ago, I realized that JWT's are not designed to be used for maintaining sessions: JWT is only a secure way of representing a claim. Imagine having a large system with tens of millions of users, and you require many servers around the world. You may have 3 authentication servers (in USA, Australia, UK). The user will then send its username and password to an authentication server, where the details will be checked in the database, and if valid it will be sent a JWT. You may then also have 10+ regular servers which handle your API. The client will then make each request to an API server with its JWT. The API server will have a copy of the secret key that was used by the authentication server to generate the JWT, and will validate your claim. Your claim is "I am authenticated". This API server will then generate a session and the client will be "logged in". The JWT may be set to expire after 5 minutes. If the user does not log in within this 5 minutes, they will not be able to log in. If they do, they will be logged in until the API server kicks them out. Whenever something happens that would cause you to want to kick the user, the API server can close the session. Even for a single-server application this is still the right way to do it. JWT are not for sessions, and you (exactly as I did) are starting to notice these seemingly unsolvable problems because you are using JWT for sessions.
Anyway, I recommend 3 or 4, both of these options have a net-positive value for many applications.
1 and 2 seem to make more problems than the benefits they provide.
But of course, it always depends on the application. If you're just making some website on fiverr for $5 then just do whatever, you know what I mean?
If there's a better solution I'd be interested to know too! Just remember that JWT represents a claim, and consider exactly what claim your client is representing.
Answering your first question (where is JWT stored in server Node.js)
JWT tokens are not stored on server side. It is a signature(by a secret key, RFC 7519 ) based authentication system.
So server just verifies the token and if it's verified then it gives access to the user and hence any user having your token can act as you.
For example - you can copy cookies/storage of a logged in facebook user and then go to another browser and set those cookies/storage. You will be logged in as that user for a few.
FYI #safebookverified 3rd way is mostly used. thanks.

How to keep user always logged in without infinite session

Wondering how this is typically implemented. Examples of always logged in websites are StackOverflow, Facebook, and Twitter. It seems like you'd have to have a background job regenerating the session ID (assuming you store session by ID in a database) before the session expires (say you tell the cookie to expire in 5 minutes). So every 5 minutes every session would be regenerated to keep it logged in while also keeping it secure. But before going down that road I'd like to know if this is how others implement it or if there is a more standard approach.
As far as I know, this is how it is done in majority of websites.
A cookie is set with an access token and limited life(of course, if the user checks on'Keep me logged in'). If the user comes to visit the site within that timespan, he is logged in and a current session is generated(from the server). And, the cookie timespan is reinitialized to the pre-decided time.
Say for example: I log in to a website example.com and check its check box, to keep me logged in. Now, as soon as I click the login button and and validated by the server, the server generates a session(for current session) and a cookie(for future sessions), with a time limit of say 1 month. Now, If i come back on say 29th day and open example.com, I shall automatically logged in using the token set in the cookie. The cookie will send my info to the server and the server shall generate my current session. Most importantly, the server will reset the cookie to expire after one month.
If, I return to the website after 30 days, then the cookie will either force me to login again.
I hope my input would be of some help to you.

Making a login session cookie id not theftable by regenerating itself repeatedly

To counteract login session cookie theft, sniffing etc i've been thinking about this scheme.
i already read http://jaspan.com/improved_persistent_login_cookie_best_practice and what i wish to do is something less-complicated, maybe performance-wise faster too and something that blends well with both remember me functionality and normal session'ed login.
when registration is successful add session id to user(:uid) table and generate session cookie id for example d6c89ddba79b4f68be07bd874c5ff566 and store it in user browser.
When user visits another,the same page,refreshes it; another id will be generated and the current id in the user(:uid) table, the cookie in the user browser will be updated with the new one making the old one useless || invalid.
If an observer tries to steal the cookie, be it in unprotected connection, for example non-https website it will be rendered useless at user's next visit or refresh.
But... i'm sure there's a flaw somewhere in this logic. can the observer create a sort of time warping technique or do something locally to annihilate the benefits of such a scheme?
One concern comes to mind now.. i think it will be a possible situation that an observer steals the cookie when the user is afk or idle, then the observer refreshes the current page with that cookie or visits another one. the problem is that now the user is logged out while the observer has full grip of his account and can therefore change password if it's not a system where password change is confirmed through email or inserting current password before.
is that right? in that case, how could this scheme be enforced without bringing possibly extra complexity?
Yes, this is a good way to prevent session sharing:
the server will generate a new Session ID to store in the cookie every n number of requests. The Set-Cookie header will only be sent once, so if there are two browsers logged into the same session, one of them will be using the old, invalid session
is that right? in that case, how could this scheme be enforced without bringing possibly extra complexity?
As you say, you can get the user to confirm their password whenever a high security function is invoked such as password change. You could also get the system to confirm their password to continue the session in the case that session sharing is detected (i.e. some requests have been logged using the old session ID).

CSRF in Go Web Applications

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.

Is it safe to store user object in a cookie?

I have a user object which contains information about the user (username, ip, country, name, email... but NOT password).
Should I store just the username in the cookie and then retrieve all info from DB upon loading the page, or just store the entire User object in the cookie?
You can't trust any information stored in a cookie, as the user can manipulate it at his/her leisure.
I suggest using a PHP session to store the object. That way, the end user only has a session ID stored in a cookie, with the real data on your server.
The session will eventually time out, though... forcing the user to log in again.
Edit: Whoops, I should point out that sessions are really easy to use. Just do the following:
session_start(); // This MUST be at the very top of every page that accesses the session
// Store something in the session with the key 'something'
$_SESSION['something'] = "Hi, I'm a session!";
// Retrieve 'something' from the session
$myString = $_SESSION['something'];
The standard rule of 'never trust posted data' applies to cookies too. I suggest storing just the user ID as well as a hash of the ID and some secret known only to the server.
For that case, I'd say store the user-id in the cookie and that's it. Then, upon first load of the page you load everything you need from the database and go on using a session as long as the user stays on your page.
To test if the page is loaded the first time, I just set a bool in the session if it has been loaded. If the bool doesn't exist, your user loads it initially.
There are probably better ways of doing this, but it works nice and easy. :)
Only store a session id! Never meaningful data such as user id. Imagine that you have a site with 10,000 users. Chances are that you have at least one user called superman and batman - if yous tore a username in a cookie to access your session information - it is potentially feasible for me to manipulate that cookie to change stored info from my username to batman and gain access to batman's account if his session is still alive. If you store some sort of randomly generated session id - it's pretty much impossible for me to figure out a session number that would work for another user to hijack that session.
You can trust information in the cookie if you use something like Hmac. Users could still see the data, but you would know if they had tampered with it (for example, changing their username to someone's else's in an attempt to see another user's data). If you don't want them to see the data, you could also symettrically encrypt the data you're sending. Obviously there's a CPU overhead to all of this, and a bandwidth overhead the more stuff you cram in there, but it's entirely legitimate to do what you're asking.
You can't assume the username being passed from a cookie is the actual username you wrote to the cookie. That is why they suggested using the sessionID. Using the sessionID you can go get the username and like he said is only good for 20 minutes or whatever you set your session timeout to be. SessionID doesn't reveal any private data. I had your same thought before I found this post though.

Resources