How do I secure sensitive information like system credentials in a configuration file?
It’s entirely true that if somebody has local access or root access to the system, they can certainly find the master key (also called the Key Encrypting Key or KEK). However, I find it is more likely that a remote attacker tries to obtain the key. There are methods that are resistant to most common remote attacks, and I recommend they are used in cases where you have sensitive information like database credentials.
The way I typically suggest this be handled is as follows:
At installation time, a random master key is generated. It is not hard-coded in the source code. It is stored on the local system either:
- in a randomly named file inside a randomly named folder, or else
- it is stored inside the metadata of a set of randomly named files
inside a randomly named folder (using a portion of the mtime
timestamp).
This master key is recovered when the system starts up, and is used to decrypt the data encrypting key (DEK). The master key is then cleared from memory. Its only purpose is to de/encrypt the DEK, which is stored in encrypted form in a config file. This DEK is used to encrypt any other secrets (like DB creds). Like the master key, the DEK is generated at installation time, encrypted with the KEK, and stored in a config file.
Advantages
- There is no hard-coded master key. Each installed agent has a different master key, so if a rogue customer purchases the product, learning the master key does no good for attacking a different customer or a different installed agent.
- If a remote attacker finds a means of exfiltrating file data, they will have difficulty given that the file name is random – typically an attacker will need to know the file name to exploit a path traversal issue, for example.
- If you store the master key in file metadata, then even if the file contents are exfiltrated, it’s useless. An attacker would require remote code execution to extract the key from file metadata. The files can be empty or (if you’re feeling like messing with attackers) can have random data – the file contents are not used, only the metadata.
How does the agent itself locate the master key, given the file name and folder name are random?
Good question!
We assume there is one folder known to the agent. Let’s say that this folder is named config/
.
Within config/, the code searches for a folder matching *.kek
. Within that folder, search for all files matching *.kpt
. Sort the filenames in alphabetical order. Retrieve the metadata from each file, and assemble the bytes into the master key.
If your master key is 256 bits, then the random file names should also have 256 bits of entropy so that a brute force search for file names is at least as difficult as a brute force search of the keyspace.
config/
…
BcFkVQ_ne5JGYj4K4W4pzMTnOYB2sYmBUQ78nu5Elo0.kek/
z2eYwmfXnJBcnC9M8fDovXV8bIG_jgDtK5656eUOplw.kpt
UUFcJYUeokiM-AzPawHGMjlMTOZAI17yBZQd48zT3_M.kpt
WD2CbKJce6iXfZuyq8Zqe3u1xQN2Op_QR1u4PCm72AA.kpt
I have a code library that does this for you. It’s in Java and is implemented using the Java KeyStore
interface. You can also implement the same thing as a C library, if that’s more suitable. We contributed the library to OWASP as open source: https://github.com/OWASP/SideKEK
A presentation talking about the system is available: https://raw.githubusercontent.com/OWASP/SideKEK/master/media/KeysUnderDoormats-slides-GlobalAppSecDC-2019-09-13.pdf
A common question is, “How is this not security by obscurity?” Security by obscurity is an attempt to keep a secret by making the method difficult to understand. Here the method is documented and can be shouted from the rooftops. The thing that is secret is the actual folder and filenames, just like a secret key in a well-documented encryption scheme like AES. A good guiding rule to follow is Kerckhoffs's principle: "A cryptosystem should be secure even if everything about the system, except the key, is public knowledge."