Ensuring that your website or open web application is secure is critical. Even simple bugs in your code can result in private information being leaked, and people are out there trying to find ways to steal data. In this article, we are going to check Django and Apache security vulnerabilities and how to fix them. This article was originally posted on my blog, The Pixel District.
Some of the checks we are going to cover can be automated using the command below so lets start by running the command:
python manage.py check --deploy
You should see some descriptions which provide information about your Django web application vulnerabilities. Note that these may not be the only vulnerabilities in your system. Here are my checklist warnings:
WARNINGS: ?: (security.W004) You have not set a value for the SECURE_HSTS_SECONDS setting. If your entire site is served only over SSL, you may want to consider setting a value and enabling HTTP Strict Transport Security. Be sure to read the documentation first; enabling HSTS carelessly can cause serious, irreversible problems. ?: (security.W008) Your SECURE_SSL_REDIRECT setting is not set to True. Unless your site should be available over both SSL and non-SSL connections, you may want to either set this setting True or configure a load balancer or reverse-proxy server to redirect all connections to HTTPS. ?: (security.W009) Your SECRET_KEY has less than 50 characters, less than 5 unique characters, or it's prefixed with 'django-insecure-' indicating that it was generated automatically by Django. Please generate a long and random SECRET_KEY, otherwise many of Django's security-critical features will be vulnerable to attack. ?: (security.W012) SESSION_COOKIE_SECURE is not set to True. Using a secure-only session cookie makes it more difficult for network traffic sniffers to hijack user sessions. ?: (security.W016) You have 'django.middleware.csrf.CsrfViewMiddleware' in your MIDDLEWARE, but you have not set CSRF_COOKIE_SECURE to True. Using a secure-only CSRF cookie makes it more difficult for network traffic sniffers to steal the CSRF token. ?: (security.W018) You should not have DEBUG set to True in deployment. ?: (security.W020) ALLOWED_HOSTS must not be empty in deployment.
Mozilla Observatory is a tool that is geared towards informing website owners of best practices for securing their sites, covering everything from personal blogs to eCommerce. The tool uses a scoring system to determine how vulnerable or how well implemented security is on your website. The site also includes third-party scanners which test other security aspects of your site.
Here is a sample scan:
If a website accepts a connection through HTTP and redirects to HTTPS, users may initially communicate with the non-encrypted version of the site before being redirected. This creates an opportunity for a man-in-the-middle attack by allowing a redirect to a malicious site instead of the secure version of the original site.
Add the code below to your settings.py file to inform the browser that it should never load a site using HTTP and should automatically convert all attempts to access the site using HTTP to HTTPS requests instead.
SECURE_HSTS_SECONDS = 15780000 # 6 Months as Recommended SECURE_HSTS_INCLUDE_SUBDOMAINS = True SECURE_HSTS_PRELOAD = True
Cross-site scripting (XSS) is a security exploit which allows an attacker to inject into a website malicious client-side code. This code is executed by the victims and lets the attackers bypass access controls and impersonate users.
To block pages from loading when they detect reflected XSS attacks, make sure django.middleware.security.SecurityMiddleware is present in middleware's list and add following lines in your settings.py:
SECURE_BROWSER_XSS_FILTER = True SECURE_CONTENT_TYPE_NOSNIFF = True
CSRF (Cross-Site Request Forgery) is an attack that impersonates a trusted user and sends a website unwanted commands. CSRF attacks typically attempt to change server state, but can also be used to gain access to sensitive data. This can be done, for example, by including malicious parameters in a URL behind a link that purports to go somewhere else.
Once you’ve set up HTTPS, add these lines in your settings.py:
CSRF_COOKIE_SECURE = True #to avoid transmitting the CSRF cookie over HTTP accidentally. SESSION_COOKIE_SECURE = True #to avoid transmitting the session cookie over HTTP accidentally.
Once you have SSL installed, you need to redirect visitors to HTTPS site. Add following line to your settings.py to force Django redirect all non-HTTPS requests to HTTPS.
SECURE_SSL_REDIRECT = True
Here is where things get interesting. Content Security Policy (CSP) is an added layer of security that helps to detect and mitigate certain types of attacks, including Cross-Site Scripting (XSS) and data injection attacks. These attacks are used for everything from data theft to site defacement to distribute malware. Having third party code creates the need of configuring CSP. This may include inline scripts and styles.
Django has an inbuilt module to implement csp headers.
First, install django-csp via pip or from source:
pip install django-csp
git clone https://github.com/mozilla/django-csp.git cd django-csp python setup.py install
Now edit your project’s settings module, to add the django-csp middleware to MIDDLEWARE, like so:
MIDDLEWARE = ( # ... 'csp.middleware.CSPMiddleware', # ... )
Note: Middleware order does not matter unless you have other middleware modifying the CSP header. That should do it! Lets go on to configuring CSP by adding following lines to your settings.py
# Content Security Policy CSP_DEFAULT_SRC = ("'none'", ) CSP_BASE_URI = ("'none'", ) CSP_FRAME_ANCESTORS = ("'none'", ) CSP_FORM_ACTION = ("'self'", ) CSP_STYLE_SRC = ("'self'", 'cdnjs.cloudflare.com','fonts.googleapis.com', 'stackpath.bootstrapcdn.com', 'getbootstrap.com') CSP_SCRIPT_SRC = ("'self'", 'ajax.googleapis.com', 'stackpath.bootstrapcdn.com', 'code.jquery.com', 'unpkg.com', 'cdnjs.cloudflare.com', 'code.jquery.com', 'getbootstrap.com') CSP_IMG_SRC = ("'self'", 'cdn0.iconfinder.com', 'media.giphy.com','res.cloudinary.com') CSP_FONT_SRC = ("'self'",'cdnjs.cloudflare.com','fonts.googleapis.com', 'fonts.gstatic.com') CSP_INCLUDE_NONCE_IN = ("script-src", "style-src")
Its really important to clean your code from all these inline styles and scripts. However, some external resources such as the ones included above may be allowed in your CSP policy. Make sure to look at the django-csp documentation in order to know what to update above as the sample above is an example of common tags loaded on the HTML page and also includes inline scripts and style. If you wish to load your scripts from source only then modify the code above to:
# Content Security Policy CSP_DEFAULT_SRC = ("'none'", ) CSP_BASE_URI = ("'none'", ) CSP_FRAME_ANCESTORS = ("'none'", ) CSP_FORM_ACTION = ("'self'", ) CSP_STYLE_SRC = ("'self'", ) CSP_SCRIPT_SRC = ("'self'", ) CSP_IMG_SRC = ("'self'", ) CSP_FONT_SRC = ("'self'", )
The secret key must be a large random value and it must be kept secret.
Make sure that the key used in production isn’t used anywhere else and avoid committing it to source control. This reduces the number of vectors from which an attacker may acquire the key.
Instead of hardcoding the secret key in your settings module, consider loading it from an environment variable:
import os SECRET_KEY = os.environ['SECRET_KEY']
Or from a file:
with open('/etc/secret_key.txt') as f: SECRET_KEY = f.read().strip()
You must never enable debug in production. Change the following lines in your settings.py file to False to disable it:
DEBUG = False
When we set DEBUG = False above, Django doesn’t work at all without a suitable value for ALLOWED_HOSTS. This setting is required to protect your site against some CSRF attacks. Change the following line on the settings.py file to point this to your website's domain.
ALLOWED_HOSTS = ['alienx.tech'] #should point to your domain name
Database connection parameters are probably different in development and in production. Database passwords are very sensitive. You should protect them exactly like we did with SECRET_KEY above. For maximum security, make sure database servers only accept connections from your application servers.
Here is my website which implements the features above:
Please note that this does not mean that our site is proof to hacking by getting an A+, this just means that our site is keeping up with the latest web security standards as per the database of vulnerabilities given by the Mozilla Observatory API. Lets us now proceed to securing our Apache Webserver. Please proceed with the commands below if you are well familiar with apache
Apache is a popular, open-source web server available for both Linux and Windows systems. It allows configuration for a diverse range of use cases, from HTML webpages to HyperText Preprocessor (PHP) dynamic web application content.Apache provides a secure and robust platform to deploy your web applications. However, it is still important to install the latest security patches and configure the server properly to establish a secure environment for your web applications.
A non-privileged user is a user that does not belong to the Dynamic Data Masking administration group. The purpose of having one is to restrict the user from unnecessary access to certain tasks within a system. In the context of an Apache web server, this means that it should work in a restricted environment with only the necessary permissions. By default, Apache runs with daemon account privileges. You can create a separate non-root user account to avoid threats in case of security attacks.
Apache is famous for providing a secure platform with a highly concerned developer community that rarely faces any security bugs. The good thing about being open source is that for every bad guy out there, there is always around 10 who are good and looking for this bugs to patch. Nevertheless, it is normal to discover issues once the software is released. Hence, it is essential to keep the web server up to date to avail the latest security features.
Run the command below:
sudo apt-get update sudo apt-get upgrade
A server signature is the public identity of your web server and contains sensitive information that could be used to exploit any known vulnerability for example your apache version. The default configuration of an Apache Server exposes a lot of details about the server and its settings.
You can disable these directives by editing the apache2.conf file via vim/nano and add the following directive:
...snip... ServerSignature Off ...snip... ServerTokens Prod ...snip...
The Directory listings displays all content saved in the root folder or sub-directories. The directory files can include sensitive information not intended for public display, such as PHP scripts, configuration files, files containing passwords, logs, etc. This directive can also be added in the .htaaccess of your main website directory
To disallow directory listings, change the Apache server configuration file by editing the apache2.conf file as:
...snip... <Directory /var/www> Options -Indexes </Directory> ...snip...
htaccess files (or "distributed configuration files") provide a way to make configuration changes on a per-directory basis. A file, containing one or more configuration directives, is placed in a particular document directory, and the directives apply to that directory, and all subdirectories thereof. In cases where a user can upload files to the server, this can be exploited by an attacker to upload his or her own “.htaccess” file with malicious configurations. So, if you are not using this feature, you can disable the .htaccess directive by editing the apache.conf file like so:
...snip... #AccessFileName .htaccess ...snip...
The default installation of an Apache server forces it to wait for requests from clients for too long, which subjects the server to Slow Loris and DoS attacks. The apache2.conf configuration file provides a directive that you can use to lower the timeout value to a few seconds to prevent these types of attacks by editing your apache2.conf file like so:
Unlimited HTTP/HTTPS requests can also lead to low server performance or a DoS attack. You can limit receiving HTTP requests per-directory by using LimitRequestBody to less than 100K. For instance to create a directive for a folder, add the LimitRequestBody directive below AllowOverride All:
...snip... <Directory /var/www/your_website> Options -Indexes AllowOverride All LimitRequestBody 995367 </Directory> ...snip...
Thats it for today folks. In the meantime, there are plenty of other ways (not listed above) to secure your Apache web server and Django Web Application, as well. Continue researching and keeping yourself updated about new directives and modules to secure your server further and keep on cross checking your website against the Mozilla observatory scan