Make sure your Django App is secure in Production

Anu Abraham
4 min readMay 24, 2020

--

Art by Akhil Mathew

Ever wondered if your Django App deployed on your prod server is secure enough to be exposed to the world.

Being a Django developer and the one who takes care of the deployment of the app on the server, I always wondered if the app that I am exposing to the internet is safe. As everyone does I went ahead and googled around for the set up for prod and I found this amazing documentation by Django, where they have a checklist of things we should consider.

Let me list out the Django deployment checklist in simple words and help you understand why it is important and help you in securing the application.

Create a settings folder with settings file for each environment.

This should be the first step that you will be doing once you start a project.

myApp
├── __init__.py
├── settings
│ ├── __init__.py
│ ├── base.py
│ ├── local.py
│ ├── production.py
│ └── test.py
├── urls.py
└── wsgi.py

Above is the folder structure diagram of how to set up the settings for each environment. Create a folder called settings inside the Project folder.

base.py will have the common setting required for all the environments like The installed app list, middleware, cache, templates, and the logging configuration if needed.

local.py and production.py will have the settings required for the appropriate environments like the database setup and to override any of the common settings we have in base.py

The command to run the Django server with different settings is .manage.py runserver — settings=settings.$env
Where env is the environment, local or production.

Create separate files for all the secrets

Have 2 files .env.local and .env.prod for local and production secrets respectively. These files can contain the DB details like the database username and password, the host, and the DB name. When it comes to prod env file we have a few more variables like DEBUG, SECRET_KEY to be saved which will be discussed in the next section.

Set the Secret Key as an environment variable

Remember to set the SECRET_KEY as an environment variable, especially for the prod settings. You can find this large random string variable in the settings file that is created when you start the Django project. We should make sure to make it unique for every environment that we set up for our project.

The secret key is used for:

  • All sessions if you are using any other session backend than django.contrib.sessions.backends.cache, or are using the default get_session_auth_hash().
  • All messages if you are using CookieStorage or FallbackStorage.
  • All PasswordResetView tokens.
  • Any usage of cryptographic signing, unless a different key is provided.

If an attacker got access to your SECRET_KEY, they could in theory tamper with Cookies, Hidden input data, etc.

For example, if you can change a plain text cookie with different data, you could make yourself the admin user. This is not desirable.

Set the DEBUG variable to False for your Prod set up

When DEBUG is enabled (DEBUG=True) and an exception is raised. A detailed traceback including a lot of metadata about your environment, such as currently defined Django settings is visible. If DEBUG=False, you also need to properly set the ALLOWED_HOSTS setting. Failing to do so will result in all requests being returned as “Bad Request (400)”. It is important to disable the debug in settings.

Set Allowed Host

Setting the list of ALLOWED_HOSTS in the settings file is required to protect your site against some CSRF attacks. The purpose of ALLOWED_HOSTS is to validate a request's HTTP Host header. Validation is done to prevent rogue users from sending fake HTTP Host headers that can potentially poison caches and password reset emails with links to malicious hosts. Since this issue can only present itself under an uncontrolled user environment (i.e. public/production servers), this validation is only done when DEBUG=False.

If you switch to DEBUG=False and ALLOWED_HOSTS is left empty, Django refuses to serve requests and instead responds with HTTP 400 bad request pages since it can't validate incoming HTTP Host headers

Change the admin URL

Change the default admin URL from /admin/ to something else. Instructions are in the Django documentation, but in short, replace admin/ in your URL conf to something else.
Once you have moved your admin site to a new URL, install the library django-admin-honeypot on your old /admin/ URL to capture attempts to hack your site. django-admin-honeypot generates a fake admin login screen and will email your site administrators whenever someone tries to log in to your old /admin/ URL.

The email generated by django-admin-honeypot will contain the attacker's IP address, so for added security, if you notice repeated login attempts from the same IP address, you can block that address from using your site.

Run manage.py check — deploy

After considering all the above steps. Execute the command .manage.py check--deploy to get a list of changes you need to make before you go ahead with the prod deployment.

I hope my attempt to simplify the checklist has helped you.

--

--