For a better reading experience, check out this article on my website.
With great power comes great responsibility. The more powerful your Django admin is, the safer it should be.
In this article I present 5 ways to protect the Django Admin from human errors and attackers.
Every framework has a fingerprint and Django is no exception. A skilled developer, an attacker or even a tech savvy user can identify a Django site by looking at things like cookies and auth URLs.
Once a site is identified as a Django site, an attacker will most likely try /admin.
To make it harder to gain access we can change the “recommended” URL to something harder to guess.
In the base url.py of the app, register the admin site under a different url:
urlpatterns += i18n_patterns(**url(r’^super-secret/’, admin.site.urls, name=’admin’),**)
Change “super-secret” to something you and your team can remember and you are done! This is definitely not the only precaution you should take, but it is a good start.
Users and admins are not perfect and mistakes happen. When you have multiple environments such as development, QA, staging and production, it’s not unlikely for an admin to perform a destructive operation in the wrong environment by accident (just ask gitlab).
To reduce the chance of mistakes, we mark different environments clearly in the admin:
Indicator in different environments
First you need to have some way of knowing which environment you are on. We have a variable called ENVIRONMENT_NAME we populate during deployment. We have another variable called ENVIRONMENT_COLOR for the indicator color.
To add the environment indicator to every page in the admin, override the base admin template:
# app/templates/admin/base_site.html
{% extends “admin/base_site.html” %}
{% block extrastyle %}
<style type=”text/css”>body:before {display: block;line-height: 35px;text-align: center;font-weight: bold;text-transform: uppercase;color: white;content: “{{ ENVIRONMENT_NAME }}”;background-color: {{ ENVIRONMENT_COLOR }};}</style>
{% endblock %}
To make the ENVIRONMENT variables from settings.py
available in the template we use a context processor:
# app/context_processors.py
from django.conf import settings
def from_settings(request):return {'ENVIRONMENT_NAME': settings.ENVIRONMENT_NAME,'ENVIRONMENT_COLOR': settings.ENVIRONMENT_COLOR,}
To register the context processor add the following in settings.py
:
TEMPLATES = [{…'OPTIONS': {'context_processors': […'app.context_processors.from_settings',],…},}]
Now when you open Django Admin you should see the indicator on top.
If you have multiple Django services that look the same, admins can easily get confused. To help admins be more aware of where they are, change the title:
# urls.py
from django.contrib import admin
admin.site.site_header = ‘Awesome Inc. Administration’admin.site.site_title = ‘Awesome Inc. Administration’
And you get:
Django Admin site with a name and a title
For more exotic options look around in the docs.
Using the same codebase you can deploy two instances of the same Django app — one only for the admin and one only for the rest of the app.
This is controversial and not as easy as the other tips. The implementation is dependent on the configuration (e.g. if you are using gunicorn or uwsgi) so I won’t go into the details.
Some reasons you might want to split the admin to its own instance are:
We split the admin from the main site only in public facing sites. We don’t bother with internal apps because it complicates the deployment and it has no benefit of being more secure.
Two factor authentication became very popular lately as many sites started offering this option. 2FA performs authentication using two things:
On first signup the user is usually asked to scan a barcode with the authenticator app. After this initial setup the app will start generating the one-time codes.
I don’t usually recommend third party packages, but a couple of months ago we started using django-otp to implement 2FA in our admin site and it’s working great for us. It’s hosted on Bitbucket so you might have missed it.
The setup is pretty simple:
pip install django-otppip install qrcode
Add django-otp to the installed apps and the middleware:
# settings.py
INSTALLED_APPS = (...‘django_otp’,‘django_otp.plugins.otp_totp’,...)
...
MIDDLEWARE = (...‘django.contrib.auth.middleware.AuthenticationMiddleware’,‘django_otp.middleware.OTPMiddleware’,...)
Name the issuer — this is the name users will see in the authenticator app, so make it distinguishable.
# settings.py
OTP_TOTP_ISSUER = ‘Awesome Inc.’
Add 2FA authentication to the admin site:
# urls.py
from django_otp.admin import OTPAdminSite
admin.site.__class__ = OTPAdminSite
Now you have a secure admin page that looks like this:
Django Admin login with OTP token
To set up a new user create a “TOTP Device” from the Django Admin. Once you are done click the QR link and you will get a screen like that:
QR for setting up a new user
Have the user scan the QR code with the authenticator app on their personal device, and they will have a fresh code generated every 30 seconds.
Making a Django admin safer and more secure doesn’t have to be hard — you just have to pay attention. Some of the tips mentioned here are very easy to set up and they go a long way.
For more Django Admin gems check out
Things You Must Know About Django Admin As Your App Gets Bigger_The Django admin is a very powerful tool. We use it for day to day operations, browsing data and support. As we grew…_medium.com
How to turn Django Admin into a lightweight dashboard_Django Admin is a powerful tool for managing data in your app. However, it was not designed with summary tables and…_medium.com
How to Add Custom Action Buttons to Django Admin_We are big fans of the Django admin interface. It’s a huge selling point for Django as it takes the load off developing…_medium.com