Django, Security and Settings
It isn't secure, anyone with access to your source control now has access to your database.
The two main methods of storing sensitive data are either with environment variables or via a json file
Excerpted from Settings - Hiding secret data using a JSON file. The original authors were Antoine Pinsard and fredley. Attribution details can be found on the contributor page. The source is licenced under CC BY-SA 3.0 and may be found in the Documentation archive. Reference topic ID: 942 and example ID: 8734.
Hiding secret data using a JSON file
When using a VCS such as Git or SVN, there are some secret data that must never be versioned (whether the repository is public or private).
Among those data, you find the SECRET_KEY
setting and the database password.
A common practice to hide these settings from version control is to create a file secrets.json
at the root of your project (thanks "Two Scoops of Django" for the idea):
{
"SECRET_KEY": "N4HE:AMk:.Ader5354DR453TH8SHTQr",
"DB_PASSWORD": "v3ry53cr3t"
}
And add it to your ignore list (.gitignore
for git):
*.py[co]
*.sw[po]
*~
/secrets.json
Then add the following function to your settings
module:
import json
import os
from django.core.exceptions import ImproperlyConfigured
with open(os.path.join(BASE_DIR, 'secrets.json')) as secrets_file:
secrets = json.load(secrets_file)
def get_secret(setting, secrets=secrets):
"""Get secret setting or fail with ImproperlyConfigured"""
try:
return secrets[setting]
except KeyError:
raise ImproperlyConfigured("Set the {} setting".format(setting))
Then fill the settings this way:
SECRET_KEY = get_secret('SECRET_KEY')
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgres',
'NAME': 'db_name',
'USER': 'username',
'PASSWORD': get_secret('DB_PASSWORD'),
},
}
Excerpted from Settings - Using Environment variables to manage Settings across servers. The original authors were sudshekhar, ssice and NBajanca. Attribution details can be found on the contributor page. The source is licenced under CC BY-SA 3.0 and may be found in the Documentation archive. Reference topic ID: 942 and example ID: 3580.
Using Environment variables to manage Settings across servers
Using environment variables is a widely used way to setting an app's config depending on it environment, as stated in The Twelve-Factor App.
As configurations are likely to change between deployment environments, this is a very interesting way to modify the configuration without having to dig in the app's source code, as well as keeping secrets outside the application files and source code repository.
In Django, the main settings are located as settings.py
in your project's folder. As it is a simple Python file, you can use Python's os
module from the standard library to access the environment (and even have appropriate defaults).
settings.py
import os
SECRET_KEY = os.environ.get('APP_SECRET_KEY', 'unsafe-secret-key')
DEBUG = os.environ.get('DJANGO_DEBUG', "True") == "True"
ALLOWED_HOSTS = os.environ.get('DJANGO_ALLOWED_HOSTS', '').split()
DATABASES = {
'default': {
'ENGINE': os.environ.get('APP_DB_ENGINE', 'django.db.backends.sqlite3'),
'NAME': os.environ.get('DB_NAME', 'db.sqlite'),
'USER': os.environ.get('DB_USER', ''),
'PASSWORD': os.environ.get('DB_PASSWORD', ''),
'HOST': os.environ.get('DB_HOST', None),
'PORT': os.environ.get('DB_PORT', None),
'CONN_MAX_AGE': 600,
}
}
With Django you can change your database technology, so that you can use sqlite3 on your development machine (and that should be a sane default for committing to a source control system). Although this is possible it is not advisable:
Backing services, such as the app’s database, queueing system, or cache, is one area where dev/prod parity is important. (The Twelve-Factor App - Dev/prod parity)
Related videos on Youtube
TheNone
Updated on July 13, 2022Comments
-
TheNone almost 2 years
From here, we add all database info as text:
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.postgresql', 'NAME': 'mydatabase', 'USER': 'mydatabaseuser', 'PASSWORD': 'mypassword', 'HOST': '127.0.0.1', 'PORT': '5432', } }
Is it a secure way? Is there any way to save this data as Encrypted data?
-
TheNone over 7 yearswhat about Encrypted data?
-
Sayse over 7 years@TheNone - What do you mean as encrypted data? Generally these two approaches are sufficient enough
-
Sayse over 7 years@TheNone - By all means, if you have a more secure solution you are more comfortable using then by all means go for it. But I have never found a need for a more secure requirement than the env variables since our production is locked down to only the most trusted. I don't see a point in having the decryption in the same place as the encrypted file
-
knbk over 7 years@TheNone To be honest, that's the wrong approach to the problem. The settings that should be secret -- your secret key, database credentials, etc. -- should be local to your deployment, so the proper solution is to keep those settings out of source control altogether. The other settings can safely live in source control without any encryption. If an attacker has access to your deployment, and not just your source control, his approach won't add any security either, since the clear-text file is needed to actually deploy the application.
-
Alouani Younes about 5 yearsPlease correct your DEBUG : DEBUG = os.environ.get('DJANGO_DEBUG','True') == 'True'
-
Toskan over 4 yearsgreat answer. I wonder though, why it isnt baked into django. I dont like the "go figure this out yourself" approach. I'd have preferred a django that is production ready out of the box, without having to jump through so many hoops