What should I use for express.cookieParser() secret? - node.js

The docs say it should be secret, but my code is published on github.
Would app.use(express.cookieParser(crypto.randomBytes(64).toString())) work, or should the secret be the same when the server restarts? Should I store the secret on disk? How secret does it need to be?

To keep your secret secret, you can set it in an environment variable (called 'COOKIE_SECRET' for example) and then you can do:
var cookieSecret = process.env.COOKIE_SECRET;
app.use(express.cookieParser( cookieSecret ));
(Or if you would like a more sophisticated config setup, you might like to take a look at nconf. It unifies configuration across environment variables, command-line arguments and flat files).

It should be the same if you want to keep sessions after a restart.
The secret is used to validate the session data on server to prevent malformed cookie data.
Maybe you can write your random data into a file and read the secret from file on app start and if file exists you dont create a new random key.

Secret is used to parse and match session cookie. If you are changing it after restart, then it will make previous sessions void as cookie will not be valid with new secret.
Still, in case if cookies were stolen, you might consider of changing secret, which sort of protects you. It is not good practice to store secret anywhere apart of place where it is needed. Same with any secrets and salts, as access to them is not good for your security.

Related

Generate a sufficient secret for JWT NodeJS Lambda

I've been looking at implementing JWT for the first time using jsonwebtoken (https://github.com/auth0/node-jsonwebtoken). For that, I need a secret value.
Is there a recommended command, or site, to generate a sufficiently good one?
I found this page (https://security.stackexchange.com/questions/95972/what-are-requirements-for-hmac-secret-key) which goes into detail about how long a secret should be (the answer seems to be a 256-bit), but where do you get one from? :)
Else it seems the other option would be to use a public/private key pair. They seem to prefer that approach on this guide I found: https://medium.com/#siddharthac6/json-web-token-jwt-the-right-way-of-implementing-with-node-js-65b8915d550e since that guy says he started off using a string and then switched to using a key pair. However the complication is this will be running on Lambda so I would ideally like the secrets (string or key) to be in environment variables. Not kept as files. But if you put a certificate in an environment variable, I wonder if AWS will strip out newlines and so screw it up when Node tries to work with it. So I'm thinking a secret string would be simpler - as long as it is sufficiently strong.
Thanks!
This is what I did when implementing HapiJS with JWT2. I generated a key based on the documentation they provided. According to their repo, this is one of the simplest ways to generate a secure key to sign against for JWT.
node -e "console.log(require('crypto').randomBytes(256).toString('base64'));"
I don't think you have to use asymmetric key authentication with public/private keys for JWT. In simplest forms, when a user logs into your system, they are given a hash of user data. On the client side, you provide that hash in the authorization header with each request. The server will check the hash to verify integrity. Since you have the key that you hashed against, it's highly unlikely that they will be able to create a forged hash.
Check out this link to the GitHub issue where they discuss generating keys for Hapi-auth-JWT2.

Generating and using a secret in a config file for JWT

I have a question regarding secrets for JWT.
I understand the "best practice" is storing the secret in an environment variable, but what about this setup?
I am generating my secret using a library called secrets.
I am storing my secret in a config file, and the relevant line looks like this
jwtSecret: process.env.JWT_SECRET || secret,
where secret = new Secret(32, true, true).generate();
Now, the way I understand this is that with this setup, my secret will be regenerated every time the server starts, essentially invalidating all previous tokens. Is this a sound setup? Is there any way that this setup will cause unnecessary grievances for my users beyond requiring them to re-authenticate? What about for me? What headaches might I face using a setup like this? I should point out that this application will likely only ever be running on one server at a time, so sharing that secret amongst multiple nodes is not a problem in my situation.
Oh and if it turns out that this is a wildly bad idea, please make it plainly evident by responding in all caps (I'm only joking, but please do make it evident).
As far as I know, you don't need (and should not) to generate secrets every time you start your server. You can just add one to your environment and that's enough.
But If you want badly to generate a secret instead of coming up with one, you can write a separate script that can be called on demand, and only by an admin behind authentication.
//maybe some authentication code here
process.env.secret = new Secret(32, true, true).generate();

Is JWT safe if someone knows the secret? If not, how can you make JWT secure?

I recently read a lot of articles talking about how JWT can be used for authentication to improve performance by not saving any session related data. Based on my understanding, it signs the data (usually user_id) with a secret to generate a JWT token. Then each client request sends the token. The server just check whether the signature can be verified and trust what's stored in the payload of the JWT.
My concern is that if someone knows your secret, he can easily create a JWT token himself and pretend to be any user in the system. One simple case is that anyone who can see the source code can easily do that. (eg: internal members)
How do you prevent it from happening? One thing I can think of is to use a randomly generated secret at each sever restart. (this may still not be secure if you sever runs a long time without changing the secret)
Many people seem to have issues with regards to the security of a JWT for this reason, and the inability to white-list/black-list people without losing the benefits from using a JWT. In regards to generating a new secret on each server restart, keep in mind that each time you change the secret, you essentially 'logout' every user who currently is logged in, or for whatever other purpose you are using it for. I think common practice is to just make sure the secret remains just that, a secret. A long, randomly generated string that is kept in a file that extremely few people have access is the best way to prevent a current secret from escaping, as far as I know.
Another thing to keep in mind is that the data is in no way hidden from anyone within the JWT. Anyone can see what you have stored so don't store any sensitive data in there. You probably already knew that from your reading, but it is an extremely easy and fatal mistake to accidentally leave sensitive data in the body of the JWT.

How and when do I generate a Node/Express cookie secret?

I'm building a node/express app and am using the express-session and mongo-connect modules to store my sessions and persist them on restart.
However, a new cookie ID is still generated every time I restart the server. I've narrowed the problem down to my session secret, which is a randomly generated string of 16 chars Here is my session code:
app.use(session({
secret: dbops.randomString(16), // generate a 16 random char string
saveUninitialized: false,
resave: true,
store: new MongoStore({
db: thisDb,
ttl: 14 * 24 * 60 * 60
})
}));
The issue is with my randomString function - when I replace it with a static string, my sessions persist through a server restart. What should my cookie secret be? Should I just pick one long randomized string and store in in an ENV variable?
I think I'm generally still confused on the purpose of the string, since my Cookie SID seems to be generated randomly anyway.
A typical session cookie looks something like this:
s%3Al3ozSdvQ83TtC5RvJ.CibaQoHtaY0H3QOB1kqR8H2A
It'll be longer than this but the format is much the same.
The s%3A at the start indicates that it is a signed cookie.
The l3ozSdvQ83TtC5RvJ is the session id (you can confirm this by checking req.session.id on the server).
The CibaQoHtaY0H3QOB1kqR8H2A is the signature.
You can think of the secret as a bit like a password used to generate the signature
In general, signing is used to confirm that the text originated from the right place. Someone might be able to tamper with the text but they wouldn't be able to sign it using the correct signature because they don't know the secret. In the context of cookies the 'origin' for the cookie is the server itself, so it just provides a way to confirm that the cookie that comes back is the same one that was sent.
However, in the context of session ids that doesn't really matter because if someone changes their session cookie it'll just mean they won't be logged in anymore because it won't match the id in the database. So why bother signing them?
Generating a random session id is actually quite difficult. Even if it looks random to you it may still be possible for someone to guess it. Signatures can help to solve this problem: how do we stop someone guessing another user's session id when the 'random' ids aren't very random?
Let's take this to a hypothetical extreme. Rather than using random session ids let's just count up, so the first session has id 1, the next session would be 2 and so forth. It's easy for someone to guess what the session ids are but that isn't enough to hijack a session. They'd also need to be able to sign it, to get something like this:
s%3A432.D5egYRj1G7sJyfbyB7jDh7Gf
The session id here is 432 and wouldn't be difficult to guess but without knowing the signature a hacker couldn't do anything with that knowledge. So signatures make it difficult to guess the cookie value even if you can guess the 'random' part.
Back to your question about express-session, as the name suggests the secret needs to be kept secret. It needs to stay the same between restarts or, as you've noticed, the signatures all become invalid and the old session cookies will all be rejected. It also needs to be the same between Nodes in a cluster as there's no guarantee that requests will always go to the same Node.
You should also be aware of the keys setting that can be used instead of secret. Using keys allows you to change the secret used to generate signatures without immediately invalidating all the existing sessions. The idea is that you specify an array of keys (secrets). Only the first one would be used for generating the signatures but all the entries would be valid for checking an incoming signature on a cookie. The idea is simply that old secrets can be included in the array for as long as they're needed and then they can be removed once we're confident that no sessions are using them.
Should I just pick one long randomized string and store it in an ENV variable?
Pretty much. It doesn't have to be crazily long but it does need to be difficult for someone to guess. It's a bit like a password but with the advantage that you don't have to be able to remember it. Ideally you'd keep the secret used in production out of the code and using an environment variable would be one way to achieve that.

JWT with Node & Passport: Restarting server

I am new to Node and trying to setup Node & Passport to create JWTs upon authentication.
I am hoping to build a "stateless authentication mechanism" to reduce the need of going back and forward to the database.
By going "stateless", if none of the shared secrets or JWT is saved in the DB, I am assuming if the server restarts, all the issued JWTs (logged in users) are invalidated, thereby requiring a new JWT for all users to access protected routes. I do not want the users to log back in each time a server restarts or a new instance is spun.
I believe I can pass in static shared secret(s) to Node environment that I can use each time to generate the same JWTs that doesn't affect server restart.
Questions:
If a good practice is to pass in the shared secrets, where and how should I create this shared secret? and what all shared secret(s) will I have to pass in?
However, if passing in shared secret(s) to Node environment is not a good strategy, I am all ears for suggestions?
Update
I meant shared secrets when I said "key(s)". I'll update the question so it's not confusing.
Actually passing the keys as environment is the recommended way for this kind of applications.
Because the environment is only be visible by the running application and reduces the possibilities of leaking the keys (compared to something like a config file provided with the rest of the application code).
Normally you don't rotate the keys that often, it's usual to rotate them once a month assuming that you control your environment.
But keep in mind that the key is only used to prove that the token was signed by you, normally is good practice to only include a tiny bit of information in the token (for performance reasons). So you still need to go to the database to retrieve extra information about the user itself. You can add all the user information inside the token but keep in mind that the token needs to be sent for each request and that adds overhead.
If you use a process manager like supervisord you can set the environments over there and give the appropriate permissions to the config file to avoid key leakage.
I normally use environments to pass that kind of information to my node applications, I use it for JWT, AWS keys, SMTP credentials, etc. It keeps your code decoupled and avoids possible mistakes like pushing private keys to public code versioning system like github.

Resources