Generate a sufficient secret for JWT NodeJS Lambda - node.js

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.

Related

What's the correct/standard practice to authenticate a user after registration?

I'm trying to authenticate a user after registration. What's the correct or standard way to go about it?
Using this method as the way to implement it, in step 3, how can I generate the random hash to send to the users email? I see two different options:
crypto
JWT token
I'm currently using JWT for login, so would it make sense to use the same token for user verification? Why or why not, and if not, what's the correct way?
The answer to your question of whether you should use a crypto hash or a token is neither.
The hash you are generating to use as a verification method does not need to be cryptographically secure, it only needs to be a unique verification hash that is not easy to guess.
In the past I have used a v4 UUID with the UUID lib and it works just fine. You could also base64 some known piece of information about the user, like their id or email concatenated with something random, like the time in mircoseconds and a random hex string with substantial length, but honestly the time it takes to build out something like that is wasted when UUID v4 works just fine.
Your hash also doesn't need to be unique (different for each user, yes, but avoid all potential collisions? No) - hitting an endpoint with only the hash is not a great idea. The endpoint should also take an identifier for your user combined with the verification hash. This way, you don't need to worry about the hash being unique in your datastore. Find user by ID, check that verification hashes match, verify. I would only suggest that you obfuscate the user's know information in a way that you can decode on your end (ex: base64 encode their user ID + email + some const string you use).
[EDIT]
Verifying or validating a user is really just asking them to prove that the email address (or phone number) they entered does in fact exist and that it belongs to the user. This is an attempt to make sure the user didn't enter the information incorrectly or that the registration is spam. For this we don't need cryptographic authentication, a simple shared secret is more than enough.
When you store your user's registration data, you generate the shared secret you will use to verify the account. This can be anything that is (relatively) unique and contains enough length and entropy that it is not easy to be guessed. We aren't encoding or encrypting information that will be unpacked later, we are doing a literal string comparison to make sure the secret we provided to the user was echoed back to us intact. This is why a simple one-way hash is OK to use. I suggested a UUID v4 because the components of this hash are generated from random information (other versions of UUID make use of the machine's MAC or the time or other known pieces of information). You can use any method you like as long as it can't be easily decoded or guessed.
After you generate the verification hash you send it to the user (in a nicely formatted URL that they only need to click) in order for them to complete their account registration. URL guidelines are totally up to you, but here are some suggestions:
BAD
/verify/<verification hash>
or
/verify?hash=<verification hash>
With only the verification hash in the URL, you are relying on this value to be globally unique in your datastore. If you can reliably generate unique values that never contain collisions, then it would be OK, but why would you want to worry about that? Don't rely on the verification hash by itself.
GOOD
/users/<id>/verify/<verification hash>
or
/users/<id>?action=verify&hash=<verification hash>
Out of these two examples you can see that the point is to provide two pieces of data, 1. is a way to identify the user, and 2. the verification hash you are checking.
In this process you start by finding the user in your datastore by ID, and then literally compare the secret you generated and stored against the value given in the URL. If the user is found and the verification hashes match, set their account to Active and you're good to go. If the user is found but the hashes don't match... either you provided a malformed URL or someone is trying to brute force your verification. What you do here is up to you, but to be safe you might regenerate the hash and send out a new email and try the process again. This leads very quickly into a black hole about how to prevent spam and misuse of your system, which is a different conversation.
The above URL schemas really only work if your user IDs are safe for public display. As a general rule you should never use your datastore IDs in a URL, especially if they are sequential INTs. There are many options for IDs that you would use in a URL like UUID v1 or HashIDs or any implementation of a short ID.
ALSO
A good way to see how this is done in the wild is to look at the emails you have received from other systems asking you to verify your own email address. Many may use the format:
/account/verify/<very long hash>
In this instance, the "very long hash" is usually generated by a library that either creates a datastore table just for the purpose of account verification (and the hash is stored in that table) or is decoded to reveal a user identifier as well as some sort of verification hash. This string is encoded in a way that is not easily reversible so it can not be guessed or brute forced. This is typically done by encoding the components with some sort of unique salt value for each string.
NOTE - while this method may be the most "secure", I only mention this because it is based on the typical methods used by third-party libs which do not make assumptions about your user data model. You can implement this style if you want, but it would be more work. My answer is focused your intent to do basic verification based on data in your user model.
BONUS
Many verification systems are also time constricted so that the verification URL expires after some period of time. This is easily able to be set up by also storing a future timestamp with your user data that is checked when the verification endpoint is hit and the user is found. What to do when an expired link is clicked is up to you, but the main benefit is to help you more easily clean up dead registrations that you know cannot be verified.

Secure HMAC shared secret by encrypting authorization hash with RSA

I am considering building an API system that uses HMAC. The server and client will have a shared secret, the client will sign the requests, the server will validate, and proceed if all is well. The trouble with this sort of system is that the secret has to be stored in a way where it can be retrieved, such as a database. If someone were to steal the secret, they have the key needed to do basically anything that user is authorized to do.
I was thinking that there must be a more secure alternative. Are there any flaws with using RSA?
Client has the "public" key instead of a shared secret. (The public key must still be kept secret for my use case.)
Client will hash the message with SHA-1 or whatever as normal.
Instead of adding the hash to the message directly, the hash will be encrypted via it's public key, and then sent with the message.
Server has the "private" key (to decrypt messages) but has no knowledge of the "public" key. (This is the part that makes this more secure than the normal approach. If the database is stolen, no keys are stolen that can impersonate a user.)
Server will decrypt the hash and validate the message as normal.
Is there anything wrong with this approach? Are there known implementations of this or something similar?
It depends on the asymmetric cryptosystem you chose:
(EC)Diffie-Hellman: It does not work. Publickey is directly derived from the privatekey via the generator, e.g. [d]G = Q
RSA: Usually people chose fixed publickeys like 0x010001. This is done for efficiency reasons. If you take a large enough, fully random e and derive d from it there is no possibility to calculate p and q given d and N OR e and N. Actually they are pretty equally then and the label private and public don't make much sense anymore. All that relies on a smmyetrical property of RSA. Be sure not to walk into textbook RSA issues. And be sure to ask enough clever people about it, this is just my thoughts on it.
If you base your crypto system on a proof of possession of a secret you need to, well - keep it secret :)
But yes, if you dont need the speed of a symmetric authentication then you can use a assymetric signature. Typically it is done with a signed hash, but you can also use a signed hmac.
The terminology is normally, that you sign with a secret key and validate with the public key (even when the signing operation looks like an encryption).

Securely storing an access token

What security measures should I put in place to ensure that, were my database to be compromised, long-life access tokens could not be stolen?
A long-life access token is as good as a username and password for a particular service, but from talking to others it seems most (myself included) store access tokens in plain text. This seems to be to be just as bad as storing a password in plain text. Obviously one cannot salt & hash the token.
Ideally I'd want to encrypt them, but I'm unsure of the best way to do this, especially on an open source project.
I imagine the answer to this question is similar to one on storing payment info and PCI compliance, but I'd also ask why there isn't more discussion of this? Perhaps I'm missing something.
Do you just want to verify a token provided by others? If so, treat it as you would a password. Use a byte derivation algorithm like Password Based Key Derivation Function 2 (PBKDF2) (also described in RFC 2898) with 10,000 iterations and store the first 20 bytes or so. When the token is received. It is not practically reversible.
Do you want to present the token to others for authentication? If so, this is a challenge because, if your application can decrypt or otherwise get access to the token, so can an attacker. Think Shannon's Maxim, the attacker knows the system, especially for an open source project.
In this case, the best approach is to encrypt the tokens with a strong algorithm (e.g. AES256), generate keys using a strong cryptographic standard random number generator and store the key(s) securely in a different location to the data, such as in a permission protected file outside the database in the example above. The latter means that SQL injection attacks will not reveal the keys.

Encryption algorithm for encypting sensitive-data - AES-256?

In one of my applications, I am to store user credentials and tokens. As the credentials are used directly on third-party services, I cannot hash them and thus need to store them as-is.
As I am not an expert on encryption, I googled and found that AES 256-bit key size-is a good idea to encrypt such data.
I would like to know the opinion of the SO community on the same, before I make a final decision.
Thanks!
Edit: Thanks to all for discussion, I am moving ahead using AES256 as the encryption mechanism for now, which seems like a good choice.
if you ask user for credential every time, then why do you need to store them in db? just keep it in memory and pass to external system. you can even ask user once and keep their password in memory for the whole session. if, for some reason you have to store them in db, them of course encrypt it. as far as i know, current standard is AES256. but still somewhere you have to keep unencrypted key.
to sum up: if you want to authenticate users and then use their password only for the time of session then you don't have to store it in database. keep salted hash for authentication purpose and keep user provided password in session for external systems
btw. is your swap encrypted?

How to have my deployed application securely encrypt a password and then decrypt it later for automation use

This question has been answered before but the key difference may be that I want to be able to decrypt the password later on and that this is for a deployed application where someone could get a handle on the code assemblies (as opposed to a website behind a firewall)
Basically, I want my application, when deployed, to accept a user password. I want to store that user password somewhere (encrypted) and then decrypt it later for use in an automation routine.
I'll make a few assumptions to simplify things. You can assume that the password in memory is secure (while it is in memory) and that a strong hasing algorithm (feel free to name the best options) is sufficient. Even so, what would prevent someone from reflecting my code and finding the hash key or technique i'm using to decrypt the password (would i even store the hashkey in the code?). I could obfuscate but my understanding is that it is still possible to read. Also, note that one way encryption is not sufficient here. I need to decrypt and use the password later on. Any ideas?
To directly answer the question, you're looking for asymmetric encryption (not hashing which is a one-way process) if you want to encrypt then decrypt your data. The OWASP Top 10 on Insecure Cryptographic Storage is a good jumping off point to learn more about this.
Now to indirectly answer your question, don't do this! Passwords should be stored with a strong cryptographic hash function including a random salt (you'll see this mentioned in the OWASP link as well). If you're trying to return password ciphertext to plain text text then authenticate to other services whilst impersonating someone else, you're missing the root cause of your problem. You've not provided much info on this but it seems the question you should be asking is how you (securely) go about identity impersonation and authentication to a downstream service.

Resources