Allow the user to stay signed in forever - Different implementation methods - session

I am developing an application and I'd like to offer the user a possibility to stay signed in forever. If he checks a box, his session should never end, unless he manually logs out or deletes the cookie. If he doesn't, his session cookie will expire on closing the browser.
I considered three ways to realise this, but all of them contain pros and cons:
Saving a cookie with the user name and his hashed password:
Pro: The user can have multiple active sessions on different devices.
Con: If the cookie gets leaked by third parties, they can regenerate his session at any time unless he changes his password.
Generating a token which will be stored in the database and in the user's cookies. Then compare them:
Pro: As soon as the user logs out, the token will be randomized and all of his sessions will be destroyed. He will definitely be logged of.
Con: The user can only log in forever with one device. As soon as he logs in from another device, accepting to be logged in forever, his other token will be overwritten.
Only hypothetically: Save sessions forever on the server and give non-expiring cookies to the user.
Con: This is probably not realistic, because you can't store that much data in an efficient way.
I currently prefer the second way, because it does not seem to be as insecure as the first one and it's easily implementable. But I am still not convinced of it and I have seen that there are proven frameworks which do it another way.
Could you imagine another way which is maybe even better? What's your favorite and why?

Never save the password in a cookie. The second method is fine, and is how I think you'll find most apps implement this feature. Note that the session storage doesn't need to be a database. The cookie contains some unique (unguessable!) id, and this id points to some unique storage. It could be a text file in a directory somewhere, a database row, a JSON string in memcached, whatever.
Pro: As soon as the user logs out, the token will be randomized and
all of his sessions will be destroyed. He will definitely be logged
of.
Con: The user can only log in forever with one device. As soon as
he logs in from another device, accepting to be logged in forever,
his other token will be overwritten.
Don't store the token id as a column in the user table. Instead create a new cross table that allows more than one session per user. So, each device will have its own separate token, and thus, its own separate session which can be managed individually.
When a user logs out, you destroy only that one cookie and its associated session store. Any other sessions that the user has outstanding will remain untouched.

Related

How to get all login users sessions in Asp.Net Core 2.2?

I have site on Asp.Net Core 2.2 using Sessions.
Is there any way to get all users sessions, and all login users and iterate them?
Also break session for some user, if he is banned.
Simply, no. A user's authenticated state is persisted only via a local cookie on the client. There is no sort of "master list" of logged in users. However, if you like, you can create an additional table or otherwise log user logins and logouts, which you can then refer to for this information. It won't end up being totally accurate, particularly with logouts, because the user's auth could simply timeout, requiring no action that you could tie into to log that that that happened. However, if you have a known auth expiration, say 20 minutes, you can assume any login older than that time frame is no longer valid. That assumes an absolute expiration, which is the default. If there's a sliding expiration, you'll need to do even more work to keep some sort of user activity record.
Long and short, it's not trivial, but can be done if you really need the information.
As far as auto-logouts go, that merely requires invalidating the security stamp. This will effectually invalidate the user's auth cookie, forcing them to have to login again. At that point, you can check their "banned" status, however that would be done, and opt to reject their login attempt.
await _userManager.UpdateSecurityStampAsync(userId);
However, that will not take effect immediately, since the security stamp is not revalidated with each request. You can make that happen by setting the validation interval to zero in Startup.cs:
services.Configure<IdentityOptions>(options =>
{
options.SecurityStampValidationInterval = TimeSpan.FromSeconds(0);
});
However, that has a performance cost, as each request will require hitting the database to check the security stamp. You may want to set a more reasonable interval that balances wanting to logout a banned user as quickly as possible without requiring making excessive database requests.

How to handle unique user sessions during login in Parse.com?

While working on a game, we needed to enforce that each user has at most one active session in one installation.
Ideally if an user tried to login while they had another active session, we should stop the login process and prompt them to what they prefer: continue the login and possibly lose unsaved data from the old session, or abort the login and keep the old session active.
However, in order to view the user's sessions, we need to log them in first. This important for security reasons, and is totally fine since a priori we should be able to do something like this:
Log the user in.
In an "afterLogin" trigger, check to see if there are any old active sessions from different installations.
If there are, abort the login (logging them out) with a particular error code/message.
Upon receiving this error code, the app could prompt the user, asking which session they prefer keeping.
The user may abort the login, in which case we should do nothing, or they may decide to use this new session, in which case we could send a login request passing an extra parameter to indicate we're forcing a new session.
We log the user in again, and since we received this extra parameter, the "beforeLogin" trigger would know to revoke and delete any old sessions.
The problem is that, obviously, there are no "beforeLogin" and "afterLogin" triggers. There's also no way to pass extra parameters to the login request.
We can work around this by calling a cloud function that handles the sessions in the login success callback in the app... but then it's easy to think of scenarios where an user ends up fully logged in with two sessions from two different installations, and we end up having to deal with them.
We also thought of logging them in via a cloud function, but that too seemed to bring more problems rather than solving them.
Is there any better way to do this?

JWT and one(!) session per user / no concurrent sessions

Our current app uses HTTP sessions and we'd like to replace that with JWT.
The setup allows only a single session per user. This means:
User signs in at Device 1
User is logged in at Device 1 (new Session created)
User signs in at Device 2
User is logged in at Device 2 (new Session created)
User is not logged in at Device 1 (Session got destroyed)
This works because there's a server-side relation between session id and user id.
Using JWT I could imagine to have some counter inside the user database, which gets increased with every login, i.e.:
User signs in at Device 1
JWT tokens signature contains counter+1 (and save new counter to database)
User signs in at Device 2
JWT's signature contains counter+1 and it gets increased and saved to db.
Now with every request I have to check if the incoming signature is correct for the current counter value.
This somehow makes it stateful. :(
But ... one of JWT's benefits is, that there's no need to access any database or session store for validating the token.
Is there some other solution for preventing concurrent logins? Maybe something that works without database access and keeps it stateless?
You are very close to the solution.
To do this you need the following:
1. Include iat in the token (Time when the token was issued)
2. Somewhere store the time when the user last logged in, for example in the user's profile.
Now when validating the token, do an extra check: iat (Issued At) must be at or later than the last login time. This implicitly invalidates older tokens.
First of all, when using JWTs for session, it's important to define:
Stateless Token: Contains all the session data inside the token. This
way you don't need to store it anywhere.
Steteful Token: Contains a session id. When the server receives the
token he will need to retrieve the information about the session.
If you are using a stateful solution in order to invalidate a token you could query the DB for the last session ID for that user and compare with the received token.
In a stateless solution, as the other answers pointed out, you will probably need to persist the state somewhere. But in comparison with a Stateful Token you only need to store a counter like you suggested or a "last_login" like #The Tahaan suggested.
If you feel that using a DB is too heavy, I recommend using an in-memory solution like Redis, which besides being very fast it has the capability of easily setting a duration for the persisted data. This way the user would have to login again if:
User signs in in another device.
A certain time elapsed.
What about closing the session of the user on any other device.
What about. every time user login, you saving the last login by type of device, and send a push notification to all the devices connected of the same type (supposedly one)?
In this case on a browser, You can send the push notification to the browser, just check what happens if that browser is closed at the moment?
In the case of mobile apps, you can send a push notification to the mobile app's with the instruction to close
This is a different solution that may be a closer fit in some situations.
You still need to go to the DB, but assuming that most of your users have only one device and only some have a second device, you can use the following strategy:
During Login (New Token Request) let the client supply a device-id. Compare this with the "last_device" value of the user. If it is different it means the user has changed to a new device.
When this happens, add an epoc entry for this user in a special table.
userid: unique reference user(id) not null
epoc: timestamp
The idea is that this table could possibly be much smaller than the full user table. Only users with more than one device logged in recently will have an entry in this table. So scanning this table is efficient. After validating the token the normal way, check that the iat (Issued At) is not before the user's session epoc. If it is, then the device is not the most recent logged in device.
This solution has other uses: It allows a user to remotely log out themselves (You create a new entry for the user with the current time which effectively invalidates all existing tokens for them).
Maintain this table by deleting items that are older than the maximum lifetime of any token regularly.
How I think it can be done.
Just create a random id (lets call this validation code) and store it in DB whenever jwt is generated.
Encode this in JWT.
whenever any request is made with jwt check if the validation code encoded in jwt matches in DB.
If user tries to login to other device it will regenerate the validation code, expiring all other sessions.

Express.js + Passport.js : How to restrict multiple login by the same user?

Passport by default allows the same user to login from multiple browsers and have unique sessions created. How can I configure it to destroy the first session when the user tries to create a second session?
Currently I'm using the 'Sessions' model to add the username to the record and upon subsequent login check by username if the sessions exists. But this increases traffic to the db. I'm thinking express must be doing it already or made to, keep the 'logged in users' information in memory so that the process can be simplified. I'd be thankful for ideas around how to achieve tweak with express for this purpose or any other workaround/suggestion.
Much thanks!
I saw that at least 4 users upvote this question, so I decided to create passport-strategy for that. The new strategy called passport-one-session-per-user. It's open source strategy you can access here: https://github.com/AminaG/passport-one-session-per-user
How to use it? add it right after session. For example:
app.use(passport.session())
var passportOneSessionPerUser=require('passport-one-session-per-user')
passport.use(new passportOneSessionPerUser())
app.use(passport.authenticate('passport-one-session-per-user'))
Not need for settings, or configuration.
How it is works?
The strategy, created an array that contain serializaed user objects, and sessionID.
Every time user logged in, the strategy check if the user already logged in. If so, it's flag the other session. The next time the user in the other session make a request, the strategy see the flag, and log the user out.
I'm thinking express must be doing it already or made to, keep the 'logged in users' information in memory so that the process can be simplified.
I believe the session model loggs the user in, and saves only that logged-in-ness in the session cookie. The server itself has no clue about who is logged in, but just checks this state in the (signed) session cookie provided by the browser.
You can write your own Passport.js strategy to handle it differently.

GWT: Storing Session ID in cookie, and then what?

I'm currently making a site using GWT, being hosted on AppEngine. I'm making it with my own logins that I'm making (I know Google provides something with GWT, but I need my own login system), and I've been trying to figure out sessions for quite a while now. I've found a few tutorials, and one of the sites that I was reading is http://code.google.com/p/google-web-toolkit-incubator/wiki/LoginSecurityFAQ
There is a section there on "How to Remember Logins". I know how to get the session ID and store it on the client in a cookie through an RPC call. What I don't understand is, eventually after a day or so, the user comes back and I'm supposed to get the session ID from the cookie and send it back to the server. What am I supposed to do on the server in order to securely evaluate if session ID is still legal, and pull up all the necessary information about the user?
Additional questions:
1. What would make the session ID change?
2. What if the user was on a laptop, and the user went somewhere else. Would he still be able to be securely logged back in without having to type in his login and password again?
Thanks!
~Scott
Similar question: question on GWT, Cookies and webpage directing.
One important thing you should remember: don't rely on cookies alone - transfer the session ID/token in the payload of the request too and compare it with the cookie value on the server side. This will prevent XSRF attacks. That's the sort of thing you should be worried about.
The policy on how to deal with session IDs depends on how seriously you take security in your application and what type of application is it. For example, you can login with the same token on GMail from different IPs - I presume they allowed this because it's common that the user's IP changes over sessions. They did however add a feature that allows you to see from which IPs the user logged in recently. And don't forget about users with dynamic IPs (quite a large number) - if you keep track of tokens and IPs you will basically disallow those users to be kept logged in between sessions.
What am I supposed to do on the server
in order to securely evaluate if
session ID is still legal, and pull up
all the necessary information about
the user?
You should keep track of the session IDs/login pairs in your DB.
What would make the session ID change?
Either it expires or the user tries to log in with a token that is not bound to their IP. You could add your own rules too - like the number of logins, etc. For additional security, you can generate a new session ID/token on every new login/session (the user authenticates with the old token, the server checks that it's valid and sends back the user the new token he/she should use from now on).
To remember logins you need to securely generate a unique session id. Normally, this is placed in a cookie. I would recommend using a framework that does session cookies for you. Getting it wrong can leave your site wide open to abuse. Things to consider include:
Do you need to worry about cookie stealing. The user's IP address should be encoded in the session id, or linked to the session id. Check the IP address on every page access.
Ensure your logins are on encrypted sessions. Otherwise, you expose credentials in plaintext on the network.
How long should sessions last. They should time out after a fixed time limit. This can be hours or days long.
Remember me should be different functionality on a different cookie. It needs to contain something that can be used to indentify the user. Depending on your security requirments it may need to be an encrypted value. This cookie can have a longer timeout.
Answers to your additional questions are.
Nothing on the client side is likely to change the session id. The session id should be regenerated every login.
Depending on how secure the session id is, they may have to login. Secure session cookies often encode the IP address to prevent cookie stealing. If so, the laptop user would need to login again.

Resources