34

I was building a RESTful Web Service when I came across JSON Web Tokens as an alternative to traditional cookies for authentication. The conceptual core of this method is that the server is the only agent that knows the secret key used to digest (commonly done using HS256) the payload, so only he can determine if the client altered the content of the message. My concern with this approach is: How can I securely store the secret key used by the server to encrypt the payload? Should I change it periodically? Should I generate it 'randomly'?

I thought of generating a 'random' string when my RESTful Web Service is initialized and storing it in a 'global variable' used afterwards to digest my payloads. However, I fear the possibility of another process accessing my REST api 'memory space' or that my operative system's virtual memory feature exposes my secret key.

kc2001
  • 117
  • 6
NMO
  • 443
  • 1
  • 4
  • 5

1 Answers1

36

The reality is if other processes can access your process memory or features of your virtual machine, the game is probably over as you're already compromised. If a process has access at this level, it can probably gain other information, such as the initial credentials used to authenticate before obtaining the token or just modifying results to make token verification return true despite the actual verification result etc. Don't focus too much on extreme possibilities. Most compromises occur through far simpler exploits or configuration errors, such as storing the private key on the file system which is world readable and accessible to your web server etc.

The best way to manage keys and secrets will depend a little on your platform. Some platforms provide key management frameworks and perhaps using one of those would be appropriate.

Don't focus too much on the fact this is a secret key. In reality, it is no more critical than other credentials you need to manage. For example, how do you manage the credentials which allow access to your databases? If that solution is good enough for your databases, then it is probably good enough for your secret key. If it isn't, then I'd be asking whether it is actually good enough for your database. The reality is, if someone is going to compromise the system, then it is likely they are doing so to gain access to whatever data/service the interface is providing. In most cases, this underlying service or database also needs credentials and credential management and these are the real keys to the kingdom.

I think it is best to use a consistent approach to manage all the credentials your application needs and not to treat the secret key for token creation/verification as extra special. Don't over think the solution simply because it involves words like 'key' or 'secret'. All credentials are sensitive data which need to be managed in a secure manner. A large proportion of the mistakes that are made are due to over engineered complex solutions that become difficult to maintain and easy to get wrong. Consider solutions which use existing, known and tested facilities/frameworks, such as keytool, key chain managers etc. Failing that, use something which can be easily understood and maintained. Something as simple as a database may be sufficient. Avoid solutions which involve storing the information as constants or global variables as this can become difficult to maintain because changing the key now means a code change and now you have to test, do change management and promote to production, etc.

As to how you generate the keys, well that will depend on your environment and the types/levels of risks you need to manage. As a rule of thumb, I'm always very wary of anything that relies on 'random'. Generating true random values is extremely difficult and often doesn't do anything to improve security. In fact, assumptions of randomness which have later proved to not be random can reveal patterns, which in turn means the possibility of being able to predict future values, which is almost always a bad thing when you're talking about keys. In this scenario, I don't think randomness is going to gain you much from a security perspective unless you're in an environment where it is critical that sys admins don't know the key. Likewise, regular changing of the key is unlikely to provide much other than inconvenience for your users. Whenever you change the key, all currently issued tokens will become invalid. You might want to consider having a policy to change the key when staff leave or change roles and you could even consider a policy to change the key whenever the software is updated, etc.
However, religiously changing the key every week or so is unlikely to provide anything with respect to security.

Note that the above does not hold true for all keys. There are situations where a private key needs to be managed with extreme care - for example, the private key for root CA. Not all keys are equal. Your management approach needs to match the requirements and risks you need to protect against. In the case of JWT, you are dealing with a largely closed ecosystem - the key is used to generate/sign and verify tokens. The objective is about detection of tampering, not protection of secrecy. The risk is that if someone gets the key, they can create forged tokens and gain unauthorised access to your service. What this ultimately means depends on the service. The extent to which someone will try to do this also depends on the underlying service and its perceived value. The lengths you go to to secure the key should reflect the threat.

Tim X
  • 3,242
  • 13
  • 13