4

I have a NodeJS app which accesses several databases. At the moment I've used dotenv to store the database passwords in environment variables to avoid saving them in source code (and avoid committing them to the repo).

However, this still stores the passwords in plain text in the .env file, which sits on the server in the app root. If the server was ever compromised the passwords would be there for someone to use to connect directly to the databases.

Is the way to solve this problem, by somehow encrypting the passwords, saving the encrypted string in the environment variables, and have the server (Node) decrypt them before they're used in the connection strings..?

I believe that when something is encrypted, it can always be decrypted. However, doing this avoids storing the passwords in plain text, so they couldn't be used as-is to connect to the database.

Recommendations for npm modules would be great. I've found crypto-js and forge, but I don't know what I should be using.

Is this a professional solution..? What type of encryption should I be using..?

1
  • re: secure , theres a diff between vars that are set from admin dashboard and vars passed using the fs ".env" more on topic @ indiehackers.com/post/… Commented Jan 4, 2021 at 14:22

2 Answers 2

2

You are correct, You are not supposed to use dotenv in production at all. Move all the "secret keys" to the machine you running. Most deployment services use something called environment variables (heroku, AWS, Azure, Netlify) where you can mark them as sensitive. Some services like azure have special services like Azure Key Vault where the keys are encrypted and can be injected into the project via dev ops build or directly into vps or app service.

If you are using custom VPS or something like that, then you set up those like any regular linux machine vars, either add env vars to server start method or edit your bashrc.

Now the main reason to do this way is to actually protect you from Repository security breach. Thats why its imperative never to store any keys or save .env file to repo. Even if you encrypt the keys they will be stored in plain text somewhere in the code / repo.

When someone gains root privileges by escalation or any other method, there is nothing you can do stop them from reading bashrc or look into the server code, so basically game over.

If you are worried about your databases, most probably you can whitelist / blacklist IPs or any other means to limit traffic from external sources, encrypt the database, make sure you have no known vulns in the project, use ssl connection, cors settings (basically properly secure your server).

Important topics to cover here is to learn is the difference between build and runtime variables. Runtime vars will be injected called from the envs vars, and build will be injected into the final code.

You could add encryption as another layer of security but only if the secret and password are kept separately. Dotenv file should be used for local development only.

Sign up to request clarification or add additional context in comments.

5 Comments

I'm not saving my .env to my repo. The dotenv npm module doesn't mention to avoid using it in production, unless I've missed it somewhere in their README.
So, the issue here is where to store the secret key, right..? The app will be running on a virtual windows server, so are you saying I should add the secret key to an environment variable on this server..?
If the server itself is compromised, couldn't the attacker just read the server environment variables..? How is that different to the secret key being in the app config..?
Well it guess it depends on the what do you mean by comprised ? Do you mean something like Path Traversal ? Where attacker can read and execute files on the server through unprotected paths / routes ? Then usually the advantage is that bash and server config files need admin rights. Let me ask you this, if an attacker can in whatever way gain root access then he basically can do anything at this point, maybe the encryption will hold him of for some time, so whats the point of this ?
And just to be sure, encryption is a good idea that can slow down attacker but only if you do not secret and pass together.
1

Simply first encrypt your password and store in env file then decrypt it whenever you need using crypto-js.

var CryptoJS = require("crypto-js");
var data = "password";

var encrypted = CryptoJS.AES.encrypt(data, "my-secret");
console.log(encrypted.toString());

copy encrypted string and past in env.

Decrypt password

var decrypted = CryptoJS.AES.decrypt(process.env.PASS, "my-secret");
var object = decrypted.toString(CryptoJS.enc.Utf8);

It can be decrypt only if secret key is match like JWT.

3 Comments

This is incorrect and will gain you nothing, as soon as someone gets their hands on the repo, they have the key, they have the password. If the managed to get root rights on the server they will just look for the env file and get the password and secret. Get the secrets out of the project.
Most of cloud server provide features to set environment variable. So no need to worry about env file.
then how to to store "my-secret" and use them again securely?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.