DEV Community

Discussion on: How to handle secrets in Node.js 🗝️🗝️🗝️ (environment variables)

Collapse
 
crussell52 profile image
Chris Russell

@benjaminmock, thanks for taking the time to share with us! This comment runs contrary to the advice in your post. It is not intended to judge you or discourage you from sharing with the community. It is only intended to educate on the not-discussed-enough risks of secrets in environment variables. ❤️

Environment variables are a popular and convenient way to configure an application and I encourage their use. But don't use them for your secrets.

The idea of using ENV for secrets has become prolific in the last few years. I see this recommendation, a lot. Maybe it is because of the quotability of "The Twelve-Factor App" which encourages ENV as the primary vehicle for configuration... or maybe it is because ENV is so convenient when it comes to containerized apps. But it is not good practice.

(A quick side-note, The Twelve-Factor App does not address secrets one way or another so it is not fair to say the author of that essay popularized the idea. I'm convinced that it added to the popularization of config-by-ENV. From there, I think people just made the leap to secrets because "secrets" have historically be considered part of "configuration.)

Why is this bad practice? Simply put, your secrets become globally available to the application (part of what makes it convenient!)... that means every package you bring in, directly or indirectly has access trivial access to your secret. A well-meaning package could simply output the entirety of the ENV in an error case to help with problem-identification and now you unexpectedly have secrets sitting in a log somewhere. A nefarious package could capture the entire ENV in search of secrets, perhaps even looking for specific key phrases in the env variables name.

Many application also spawn child processes. Unless you are careful about it, your ENV becomes the env of the child process. This inheritance behavior is fundamental to the env. Some security-minded programs will include mechanisms to prevent this inheritance (sudo does this) but most do not -- mainly because env inheritance is expected. But not for secrets. Try the following.

// parent.js
const {execFileSync} = require('child_process');
console.log('parent', process.env["FOO"]);
console.log(execFileSync('node', ['child.js']).toString());
Enter fullscreen mode Exit fullscreen mode
// child.js
console.log('child', process.env["FOO"]);
Enter fullscreen mode Exit fullscreen mode
// command-line
FOO="mySecret" node parent.js
Enter fullscreen mode Exit fullscreen mode

See points above about well-meaning, and bad-intentioned libs and extend that to other processes you may spawn.

Instead, put your secrets in a file and secure that file using appropriate access control. Load that file when you need the secrets.

At the end of the day, my advice is: Use environment variables for configuration. Do not use them for secrets.

P.S. Here's some other posts by not-me on this subject: