Avoid Putting Credentials in Code

Vee Huen PhanVee Huen Phan
4 min read

by Vee H. Phan

Photo by Arget on Unsplash

Recently I was working on a codebase that had database credentials hardcoded in connection strings. Not only is the connection string hardcoded with credentials, but it is also repeated in multiple places in the codebase. Two sins are committed here:

1. Hardcoding credentials in the codebase

This is a bad practice because it exposes sensitive information such as database credentials. Hardcoding credentials in the codebase makes it easy for attackers to access the database and steal sensitive information. This is a security risk and should be avoided.

2. Repeating the same connection string in multiple places

One of the basic principles of software development is DRY (Don't Repeat Yourself). Repeating the same code, in this case a connection string, in multiple places violates this principle. If the connection string needs to be changed, it would have to be changed in multiple places. This is not only time-consuming but also error-prone.

Solution: Use environment variables

Use a .env file in a project codebase

A method to prevent hardcoding credentials in the codebase is to utilize environment variables. One approach to set environment variables is by using a .env file within the project. This file contains key-value pairs of environment variables and should not be included in version control. To ensure this, add it to the .gitignore file.

In the root directory of the codebase, the .env file can be created with the environment variables. Sample .env file with database credentials:

DB_HOST=localhost
DB_USER=root
DB_PASSWORD=password
DB_NAME=mydatabase

DB_CONNECTION_STRING=postgressql://$DB_USER:$DB_PASSWORD@$DB_HOST/$DB_NAME

To load the environment variables from the .env file, there are a number of python package can be used. They are:

  • python-dotenv
  • python-decouple
  • envparse

My go-to package is python-dotenv. The python-dotenv package is a Python library that loads environment variables from a .env file into the os.environ dictionary. The python-dotenv package is easy to use and works well with Python projects. To use the python-dotenv package, it can be installed using pip:

    pip install python-dotenv
import os
from dotenv import load_dotenv

load_dotenv()

db_host = os.getenv("DB_HOST")
db_user = os.getenv("DB_USER")
db_password = os.getenv("DB_PASSWORD")
db_name = os.getenv("DB_NAME")

connection_string = os.getenv("DB_CONNECTION_STRING")

This way, the credentials are not hardcoded in the codebase and can be changed easily in the .env file. The connection string is defined in one place and can be reused in multiple places within the same codebase.

Use a .env file located outside the codebase

One can also store the .env file in a secure location and load the environment variables from the .env file using the load_dotenv(dotenv_path="path/to/.env") function. This way, the .env is located outside the codebase and will not be checked into version control. Other codebase within the same machine can also use the same .env file to load the environment variables, effectively one only needs one .env file for multiple codebases.

import os

from dotenv import load_dotenv

load_dotenv(dotenv_path="/path/to/.env")

In this case, the path to the .env file must be specified in the load_dotenv() function. The disadvantage is that the path to the .env file must be specified in the codebase. If the path changes, the codebase must be updated.

Set the environment variables in the .bashrc or .bash_profile file

Another way to set environment variables is to set them in the .bashrc or .bash_profile file. The .bashrc file is a shell script that is executed when a new terminal is opened. The environment variables can be set in the .bashrc file using the export command.

To add the environment variables to the .bashrc or .bash_profile file, open the file in a text editor and add the export command for each environment variable. For example, to set the DB_HOST environment variable, add the following lines to the .bashrc or .bash_profile file:

export DB_HOST=localhost
export DB_USER=root
export DB_PASSWORD=password
export DB_NAME=mydatabase

export DB_CONNECTION_STRING=postgressql://$DB_USER:$DB_PASSWORD@$DB_HOST/$DB_NAME

After adding the environment variables to the .bashrc or .bash_profile file, save the file and run the source command to apply the changes to the current shell session. The source command reads and executes the commands in the .bashrc or .bash_profile file in the current shell session. To run the source command, open a terminal and run the following command:

source ~/.bashrc

The environment variables are set automatically each time a new terminal is opened, and they are available to all codebases. The environment variables can be accessed in the codebase using the os.environ dictionary. For example, to access the DB_CONNECTION_STRING environment variable, use the following code:

import os

CONN_STR = os.environ.get("DB_CONNECTION_STRING")

Finally, configurations pertaining to a project can be stored within a configuration file, such as a settings.py file, and the environment variables can be loaded in the settings.py file using the os.environ dictionary. All other modules can then import the connection string (or any other configurations) from the settings.py file.

Conclusion

Avoid hardcoding credentials in the codebase. Use environment variables to store credentials and other sensitive information. Environment variables are a secure way to store sensitive information and make it easy to change the information in the future. Environment variables can be set in a .env file in the codebase, or in a secure location outside the codebase, or in the .bashrc file. By using environment variables, the codebase is more secure and easier to maintain.

1
Subscribe to my newsletter

Read articles from Vee Huen Phan directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Vee Huen Phan
Vee Huen Phan