Is there any way to remove or expire the httpOnly cookie stored in the client when reaching the server from another client (e.g. 2 different browsers)?
I want to create a "logout all" button that logs out the user from every device, by now I'm storing the cookies in the database and removing them from database when the user clicks in "logout all" an then I authenticate only if the cookie is stored in the database. Is this approach enough? Is there any security issues with it?
You can't delete HTTP-only cookies without a request from the browser that has them. HTTP-only cookies are only modifiable via the Set-Cookie header.
By now I'm storing the cookies in the database and removing them from database when the user clicks in "logout all" an then I authenticate only if the cookie is stored in the database. Is this approach enough? Is there any security issues with it?
It depends on how you are generating them. If you're using a CSPRNG to generate a random token, that approach is secure and recommended, because if an attacker gets access to a computer the user logged in from, the user can revoke the token (assuming that the password cannot be changed using the token).
Related
I am currently building a Node.js application and trying to use JWT to handle sessions. In every implementation that I've seen the refresh-token is stored in a fast database like redis. When the token has expired, the client sends the refresh-token to get the new access-token, then the server checks if the refresh-token is in the database, then generates a new token.
But since the refresh-token must be generated by the server, cannot be tampered with, and we can also check if it has expired, why do we need to store it. If it is for logout then can't we just store the user_id in the database for the people who have been logged in without storing the refresh-token.
I was also thinking along the lines of storing the newest access-token instead of refresh-token in redis as value for the user_id. The reason being that we will generate a new access-token only when the previous one has expired. So the following scenario cannot happen,
User logs in, gets access-token and refresh-token.
Immediately refreshes their token while the previous one is still valid.
Logs out, and uses their old access token.
Since most implementations blacklist only the access-token provided by the client during logout, I believe this scenario can be possible if the REST API is used by the client.
So what is the use of storing the refresh-token, and would storing the access-token instead be beneficial in any way. Some more information regarding the application,
I am using redis for logged in users, and blacklisted access-token (provided during logout).
I am storing both refresh and access tokens in httpOnly cookies, and sending access tokens as bearer tokens.
refresh-token is sent in POST body while refreshing the access token.
I am not using https
Let me answer each of your questions:
"But since the refresh-token must be generated by the server, cannot be tampered with, and we can also check if it has expired, why do we need to store it":
Refresh tokens are meant to have very long expiration times (possibly months), so that users do not have to log into the application frequently (especially in the case of mobile applications). Therefore, if a malicious person steals a user's refresh token, the user's protected information will be exposed for a long time. In case this happens, a considerably secure application should have mechanisms to, for example, detect sudden changes in the IP address of its users and report them. Now, if a user confirms the existence of strange behavior in his account, it is necessary to revoke all his refresh tokens to protect his information, and to do this, it is necessary to have control of the refresh tokens that a certain user has, so they have to be stored.
"If it is for logout then can't we just store the user_id in the database for the people who have been logged in without storing the refresh-token":
You need to store both, both the "user_id" and the refresh tokens, in such a way that you can have a control of all the refresh tokens of a certain "user_id" (as stated above). If you only want to store the "user_id" of the logged in users (without storing refresh tokens), I don't know how you will check if a user is authorized to renew an access token without having to make the user log in.
"I was also thinking along the lines of storing the newest access-token instead of refresh-token...":
By doing this you are losing advantages of the "stateless" approach offered by JWTs (https://restfulapi.net/statelessness), since you are storing a state of them. If you really want something like this, it's probably best to use a "stateful" approach like sessions.
I don't see the reason to do this. Suppose you have a web application and a mobile application connected to a RESTful API, if the user logs into both applications he will have multiple valid access tokens and refresh tokens, so it is perfectly normal for a user to have multiple valid tokens at the same time.
If a user logs out, simply remove the access token and the refresh token from his device, additionally, remove the refresh token from the database. Use short expiration times on access tokens (15 minutes is very common), and so you have no need to store them as they will expire quickly. That's it.
I have implemented all of the code to support token rotation/ refresh with one last hitch. How are we supposed to persist the token on the frontend to make authenticated backend calls beyond our login?
My Current workflow goes as follows:
User logs in with email and password and is returned the refresh token and the access token in an HTTP-only secure cookie.
A MongoDB (body) document along with the refresh Token and Access Token in HTTP-only, secure cookies is returned with the response.
Now moving on from here how can we persist using these cookies? Especially since we cannot access these. I am using HTTP-only cookies as that is what is recommended as it is most secure but I am struggling to see how it is possible with only HTTP cookies.
In case anyone stumbles across this. HTTP cookies persist by default. They were not persisting in my case as I had the secure property set to true and I was not over an https connection.
I plan not to use HTTPS for my web app. I used digest authentication as method to secure login to my system. And after user being authenticated, I simply send nonce to them periodically(1 min). When users make request, I simply check whether the nonce expires before I send them response.
I want to know whether it is necessary for me to protect users session_id in case the attackers replay the nonce or guess out the nonce generation mechanism? And if yes, how do I secure the session_id?
Take a look at Session Hijacking and Fixation
The best solutions to Session Hijacking/Fixation is:
Regenerate session identifier at key points. In your case after user login. So, after the user logins, we give him a new session identifier.
So,in case a hacker hijacked the session id, it would be useless and
would not work.
Save User Agent/IP address and compare it against
the User Agent/IP address used just before login. A hacker would not have the same User Agent/IP address as the legit user. But remember User Agent/IP address can sometimes be faked.
Last but not the least, destroy old session regularly.
Keeping these in mind, your program will be safe from Session Hijacking/Fixation.
I have an application in which I would like to implement protection against CSRF using a security token, but also to make my application available for that same user if he opens a new tab.
When the user authenticates himself with his correct username/password combination, I add him to the session and return a cookie that contains the token. When the cookie arrives, I remove the token from the cookie and store it in a global variable. With each request I make I append the token and compare it with the one on the server.
The problem is when I open a new tab, user gets automatically removed from the session because a request that doesn't contain a correct token is received.
I understand that if I store that token in the cookie or in the localStorage I would be able to read it from another tab and the request will be valid, but I'm not sure how safe is this implementation or even which one is better? With a simple XSS you could read the token from the cookie/localStorage/global variable...
Are there any other ways I can implement a CSRF token protection and still be able to use my application from another browser tab?
With a simple XSS you could read the token from the cookie/localStorage/global variable...
If your site is vulnerable to XSS then this always supersedes any CSRF vulnerability.
As long as CSRF tokens are refreshed for every new session, there is no need to change the CSRF token once it has been used. An attacker cannot read the token so there is no extra risk.
This will enable tokens to work across tabs with no loss in security.
I'm working in a cookie-less way to manage sessions in my project (expressjs), keeping all session data server side and using a token at client side (previously generated by the server) to validate the session on every request.
A new token will be created on user login and kept hide somewhere in the page, then, on every request this token will be written to the request header and validated server side. at this point server will search for the token in a session store, lets say redis, and get the session data if the token is found or respond with a message of session expired otherwise.
There are some things i'm considering for this:
Redis keys are created on user login with a settled expiration.
Every time session data is found in redis i have to 'touch' the key
so expiration time gets postponed.
Token will be validated along side with the ip address of the client so can't be used by other person.
My question is if this is can be considered a secure way to work with, and if there is anything i'm missing here. Thanks
OK, cookies are required for storing session. Express does it the ideal way.
In express session(not cookiesession) it is completely stored at the server, only a key is sent to the client. The whole session is serialized to a key which is then sent. I assume you want that user cannot tamper with the session cookies. You can use httponly cookies to prevent tampering. They are only handled by browser and cannot be accessed by user. This prevents cookie theft or session hijacking. You can enable httponly cookies with:
app.use(express.session({cookie: { path: '/', httpOnly: true}, secret:'password'}));
Still you should use some encryption to prevent eavesdropping of cookies. Use secure : true for that. You can also mention where you want to store the session with redis, mongo or simply in memory.
The request token validation that you mention is a technique commonly used to prevent Cross-site request forgery. It keeps changing the token dynamically to keep user from getting the token. You can use this in express with csrf middleware.
app.use(express.csrf())
IP matching will not work as IP of user can change over time.