21

After reading this: JWT: What's a good secret key, and how to store it in an Node.js/Express app?, on how to store "secret key" to assign JWT tokens. I had security questions. My data (messages, username, etc...) are going to be encrypted (in database) and only authorised users can decrypt it (based on their private key). Since JWT tokens are generated using 1 "secret key" which is stored on the server, in case an attacker gets the "secret key" and get's hold of the database - tokens can be forged and therefore data can be decrypted bypassing "password", which makes encryption pointless. To protect the "secret key", I could use these methods

Method 1

Store the "secret key" on a separate server (like HSM) which will be received during login and then used to set the token

Method 2

Encrypt some kind of salt for each user and use it as the "secret key"


I'd like to hear your thoughts and ideas. How does facebook or twitter do it? Do I really need HSM to store private keys for encryption or there's some kind of alternative (eg: safe file system) ?

Community
  • 1
  • 1
Rainbow
  • 221
  • 1
  • 3
  • 10

2 Answers2

19

@SilverlightFox answer is not correct.

  1. A JWT signature verification check should fail if the X.509 Certificate used for signing is revoked (this is described clearly on the jwt.io introduction page), so JWT tokens are actually very suitable for highly secure applications contrary to the accepted answer so the entire answer is questionable at best, misleading and very harmful at worst.

  2. A HSM can generate a securely seeded secret, so that the secret is not deterministic in any way. Outside HSM's most generated secrets (if not all) are only pseudo-random and not strong enough for some cryptographic purposes. In JWT the secret generator will be the party to read data (decipher), ergo a HSM is not meant to do that, right? A client will want the clear text data not the HSM, so the client may trust a HSM to create it's secret then the client uses that secret to then create an RSA/ECDSA private key pair for JWT use. I.e. the client creates the key pair. Because the assurance is gained when only the intended reader of the sensitive data can decipher, meaning the client must hold the private key and never share it with any other party. The client will share only a public key, so that other parties can encrypt data (encipher) in a way that only the client holding the private key can decipher. Sharing a private key is poor security practice and breaks the security model making the JWT meaningless. There is an alternative to a HSM where a private CA issues an X.509 Certificate for the purposes of generating RSA/ECDSA key pairs on the client too, but again a client must securely store this and treat it as a secret.

  3. File systems are not considered secure, even when encryption at-rest is in place (because nothing is encrypted at-rest during operation of the server ergo the server is not at-rest, everything is in clear-text during operation). There are many trivial SSRF and RCE exploits available to traverse file systems of servers, both known and unknown, even software installed with defaults often allow this or are easily misconfigured before we even consider static code vulnerabilities. A secure storage is going to require data protections, i.e. purpose built security controls to assure the data is protected, and a plain text file stored on the server has no such security characteristics unless you specifically add them. Some examples is making sure that the directory owner is not the same as any process that take user input, the sensitive file is stored in a directory inaccessible by any process that takes user input, and you are running security modules like SELinux to enforce a security policy that protects this data speifically.

  4. Having a per user key is the objective of a JWT that uses RSA/ECDSA. It precisely has 1 purpose, so you're very mistaken on this point. It only exists to encipher application data in such a way that only the client requester with the private key may access it and decipher it. Any other implementation is not following JWT, and is likely applying poor PKI practices, and lacks the 1 security characteristic it was designed to apply; confidentiality. There is another type of JWT that does not require confidentiality at all, and only requires integrity via the use of HMAC and has no encryption at all, you may be misunderstanding JWT and mixing these distinct modes of JWT to form your current understanding.

Overall, this accepted answer is highly misunderstanding fundamentals of JWT and has dangerous security advice.

Answer to the question

Since JWT tokens are generated using 1 "secret key" which is stored on the server

This is not how you first explained how you implemented JWT, you said

only authorised users can decrypt it (based on their private key)

Which is it?

As described above; generating RSA/ECDSA key pairs on the client and send the public key to a server to sign the JWT, a server should never have the private key (the secret) used by a client to decipher (decrypt) the JWT.

How does facebook or twitter do it?

They are the JWT producer in an OIDC flow, i.e. they do not sign the JWT using a private key, they sign it with a public key so the holder of the private key (the OIDC consumer) can decipher the content of the JWT.

An aside; are you solving the same use case as facebook or twitter? Are you assuring identities to other 3rd parties? are you the JWT producer for the purposes of allowing your consumers trust an identity you validated? if so, you should never ever ever and i stress never know the private key of the consumers, you only need o sign the JWT with a public key provided to you.

tokens can be forged

A JWT is a token that represents a claim, it claims to be authorisation but it is not actually authorisation until verified. ergo "claims". Also JWT forgery is a strange concept, is it 'forgery" when signing JWT content is done using a public key? You may be misunderstanding the JWT modes here. There are JWTs signed using a shred-secret that produce a HMAC and both producer and consumer require the same shared-secret to reproduce a matching HMAC at both ends. This is not encryption using private and public keys, JWT has variations where a HMAc can be used and the shared-secret is in fact sensitive and if exposed can be used to forge a HMAC, but the question you asked is ot clear if you are using HMAC-style JWT or the encryption-style (RSA/ECDSA) JWT the accepted answer assumed you are using.

Further assistance

Readers and past participants; There's quite a lot to learn in the above answer, I encourage you to research more about JWT, ECDSA, RSA, HMAC, OWASP key management, Cryptography storage cheatsheet, and SAMM's secrets management.

Then ask more question in this community for more specific issues you come across.

Stof
  • 610
  • 7
  • 16
8

Depends on your risk appetite. The fact that you are using JWTs indicates that your system is not a high security system (JWTs cannot be revoked server-side very easily so are unsuitable for highly secure applications).

HSM is a good option, although you'll either need to cache it in memory to validate every subsequent page request unless you are using the RSA algorithm.

The file system may be "secure enough" given that an external attacker cannot arbitrarily access files stored on your server.

Having a per user key somewhat defeats the objective of having a client-side session state mechanism as you will have to lookup this key on every request in your database.

See also Are JWTs a secure option for user authentication?

And also this question.

Community
  • 1
  • 1
SilverlightFox
  • 32,436
  • 11
  • 76
  • 145
  • Could you please explain: **although you'll either need to cache it in memory to validate every subsequent page request unless you are using the RSA algorithm** - how RSA links to creating or storing the secret key? – aloha_mate Jun 23 '16 at 13:28
  • Well if you're using a symmetric algorithm to authenticate the user (e.g. HS256) then you'll need to check the JWT "signature" on every request in order to authenticate the user. If you're using RSA, then the private key could be in the HSM, and you could store the public key on the file system because that is not sensitive but will allow you to validate the signature in your JWT. – SilverlightFox Jun 23 '16 at 13:30
  • 1
    @Rainbow: If the attacker can execute code on your server, then yes these cases are the same. You have to assume though that if an attacker can execute code, then you are already compromised. It would mitigate the case though where a vulnerability allows file access but not code execution. – SilverlightFox Jun 23 '16 at 15:30
  • I am trying to encrypt messages, could you please answer this question: http://stackoverflow.com/questions/38013916/encrypting-chat-normal-messages – aloha_mate Jun 24 '16 at 13:21
  • > JWTs cannot be revoked server-side very easily so are unsuitable for highly secure applications Can you elaborate on why not? Isn't that the point? – Kevin Suttle Sep 28 '17 at 18:02
  • @kev. Isn't what the point? It's because there is no server side record of the token so it's not possible to revoke without server side state. This is defeating the object of storing state client side. – SilverlightFox Sep 28 '17 at 18:08
  • @SilverlightFox Ah ok. Gotcha. Thanks for the explanation. – Kevin Suttle Sep 29 '17 at 15:59