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.