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.
Related
I have an App on Parse platform. What I need:
The User logs in on first device.
The User logs in on second device.
System revokes session on the first device.
I tried to remove objects from Session/Installation classes, but it did not help.
How can I do it?
Achieving this is not quite straightforward as there is no way to intercept login events or write cloud code triggers for Parse Session class. If you delete a client session record from the Session table, it should certainly revoke it and you end up getting authentication errors on that client. To achieve what you want, you need to write your own cloud function that logs a user in instead of using the SDK login function. That way you can first go through the Session table and revoke/delete any session associated with that user before logging in your user on the new device.
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.
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.
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.
I just started looking into OAuth and it looks really nice. I have oauth with twitter working in ruby right now.
Now I'm wondering, what is the recommended safe way to store the responses in my local database and session?
What should I store?
Where should I store it?
This example twitter-oauth-with-rails app stores a user.id in the session, and the user table has the token and secret. But that seems like it'd be really easy to hack and get the secret by just passing in a slew of test user ids, no?
The tokens are useless without the consumer key/secret of your twitter app as they're not the same for every app but depend on the consumer key/secret.
To get a session variable you would have to guess the session id which is not that easy to accomplish.
If you want you can store those tokens in the session but I would suggest storing the user tokens in your database with all the other user data so your session contains only the data to identify the user in your system.
Update: I'm not sure if I understand correctly what you mean by accessing the tokens from the database by guessing an ID.
Do you have any authentication in place so that the users have to enter some credentials to access their data? You should store the tokens the same way you store the users email address or password and only authenticated users should be able to access it.
If you're developing a web application you can add a hidden field to the form the user submits, with some hash-like value calculated with the user.id so evil guys cannot change that value and just "guess" for an access token