Home
/
Blog
/
For Developers
/
Django Nginx Secure Link — open sauce

How do we hide files from public access

Django Nginx Secure Link — open sauce

Today we will reveal the secret ingredients that make our technology unique. Our SRT chef Evgeny Khatsko will tell you how to cook Django Nginx Secure Link. Have fun reading.

Module assignment

We have made the first release of our package, it can be found here. The motivation was the problem of hiding files from public access for unauthorized users, or, going deeper, hiding the file from everyone altogether by creating temporary links for each individual file.

It is possible that someone will see the feedback from the object storage in this and say "there are AWS S3, Azure Blobs, etc.", but there are some problems and difficulties that prevent the rapid integration of this kind of storage. It is not always advisable to connect object storage to a working project, here are some such examples from our experience:

  • Projects that do not require scaling can often be implemented with the simplest set of tools and technologies, without requiring the connection of additional services distributed across different nodes (object storage). Obviously reducing the complexity of the project and the number of components dependent on each other.
     
  • Projects in which working with files is only due to the exchange of some reports that are closed within a single node. In such cases, generating report files and then uploading them to the object storage looks redundant (not always, of course), because it is much easier to monitor files within a single node that is closed from public access and reduce the number of errors during their transfer.
     
  • A simple MVP project in which it is important to quickly release a product with minimal costs, without unnecessary blockers and dependencies. It is much easier to take 1 powerful server and raise all the necessary components on it, such as a DBMS, queues, an application web server, etc. In practice, this is the fastest and most efficient option in terms of speed of setup and development, of course, given the expected loads and the impossibility of horizontal scaling.
     
  • Legacy is a project in which the integration of object storage looks laborious and difficult due to older versions of the framework and its dependencies, and often the inability to integrate it at all.
     
  • And of course, projects for which object storage will only complicate working with files. As an example, we can cite the processing of a large file in the background, which entails uploading the file back to the server from the object storage in order to unpack it or perform any other processing.

This is just a small list of examples in which it is much easier to take the Nginx module by closing public access to files, adding a component for generating private links to output files to the outside, thereby not changing the entire logic of the codebase working with files. Our package allows you to delegate file protection directly to the web server on simple and not only projects where Nginx acts as a frontend server, unloading our backend.

The solution is also suitable for solutions that are quite complex in architecture, where files can be stored on separate servers, which will be accessed via Nginx.

Our package allows you to take over the generation of temporary links to files, limiting public access, and Nginx itself already checks these links and decides whether to return the file. Nginx has an excellent ngx_http_secure_link_module module for this task, but we took it as a basis and wrote a layer between Django and this module. The solution turned out to be simple and convenient, we also took into account specific cases when it is necessary to hide only specific directories from the media storage or to make them public only, all this is configured at the package level and must be configured at the Nginx level with specific locations for media/...

The package also contains auxiliary manage.py commands aimed at helping you configure the required block for location.

The work is still in full swing and improvements and edits will be made. There are several open tasks that will soon be included in the next release. If you are interested in this project and want to improve it, then write and participate. We will be glad of any involvement, you can even tweak it in order to improve the packages.

Let's dive into the technical part a bit and look at an example of configuring a Django project and configuration for an Nginx virtual host.

Step 1: Install the module

pip install django-nginx-secure-links

Step 2: Setting up a Django Project

Depending on the Django version, you need to specify the following settings:

Common settings for all Django versions

INSTALLED_APPS = (
    ...,

    'nginx_secure_links',
)
SECURE_LINK_EXPIRATION_SECONDS = 100
SECURE_LINK_SECRET_KEY = '8SypVsPwf3PypUfdVmos9NdmQNCsMG'
SECURE_LINK_TOKEN_FIELD = 'token'
SECURE_LINK_EXPIRES_FIELD = 'exp'
SECURE_LINK_PRIVATE_PREFIXES = [
    'private',
]
SECURE_LINK_PUBLIC_PREFIXES = []

  • For Django versions < 4.2:

DEFAULT_FILE_STORAGE = 'nginx_secure_links.storages.FileStorage'
  • For Django versions >= 4.2:

STORAGES = {
    "default": {
        "BACKEND": "nginx_secure_links.storages.FileStorage",
    },
    "staticfiles": {
        "BACKEND": "django.contrib.staticfiles.storage.StaticFilesStorage",
    },
}

Also, as an example, we will specify the MEDIA_URL and MEDIA_ROOT settings.:

MEDIA_URL = '/media/'
MEDIA_ROOT = '/var/www/html/media/'

Step 3: Configuring the Nginx Virtual Host File

We have added the auxiliary secure_links_gnx_location command for manage.py , which is convenient to use to automatically generate the required location block, taking into account the current settings of the Django project:

python manage.py secure_links_nginx_location

An example of a configuration block will be displayed in the console, which must be inserted into the site.conf file.:

location /media/private/ {
    secure_link $arg_token,$arg_exp;
    secure_link_md5 "$secure_link_expires$uri 8SypVsPwf3PypUfdVmos9NdmQNCsMG";
    if ($secure_link = "") {
        return 403;
    }
    if ($secure_link = "0") {
        return 410;
    }
    alias /var/www/html/media/private/;
}

location /media/ {
    alias /var/www/html/media/;
}

Step 4: Verification and Testing

1. Consider an example of a data model that saves files to a private directory specified in the SECURE_LINK_PRIVATE_PREFIXES setting.:

from django.db import models


class PrivateDocument(models.Model):
    file = models.FileField(upload_to='private/documents')

2. Create a new record in the database by uploading the file through the administrative panel for PrivateDocument.

3. To generate a secure link, just refer to the url property in the file -> obj.file.url field:

from django.http import HttpResponse
from django.shortcuts import get_object_or_404

from models import PrivateDocument


def private_document_view(request, pk):
    obj = get_object_or_404(PrivateDocument, pk=pk)
    private_url = obj.file.url
    return HttpResponse(private_url)

The private_url variable will store a private link containing two additional GET parameters.:

  • Link example: /media/private/documents/file1.txt?token=S9tBKKkXcAq77g8MrVe6LQ&exp=1721519555

  • The token GET parameter (see the SECURE_LINK_TOKEN_FIELD setting)

  • The exp GET parameter (see the SECURE_LINK_EXPIRES_FIELD setting)

It is worth considering that if the files are not in the private directories listed in the SECURE_LINK_PRIVATE_PREFIXES setting, then the private link generation will be skipped. As a result, we will get a public link without the additional GET parameters token and exp.

A full working example for different versions of Django can be found at this link. The example shows the simplest installation of the Nginx module via the nginx-extras package, but it is worth noting that if you build Nginx from source code, you can also add this module in the step./configure, avoiding installing nginx-extras on the system. We have designed a repository with an example by creating branches for specific versions of the Django framework. We hope this will simplify the integration of the package into your projects.

Frequent questions

What is Django?
What is Nginx?
What is the working principle of Nginx Secure Link?

Share

Discuss the project with the LighTech team

Book an appointment

Examples of project implementation

Tell us about your project
Name
Contact
Message
Attach file +
Request to get files
Name
Send files
Message
Thanks!
Your request has been sent
After processing, our manager will contact you