Restricting access to static files in Django/Nginx
Asked Answered
G

4

9

I am building a system that allows users to generate a documents and then download them. The documents are PDFs (not that it matters for the sake of this question) and when they are generated I store them on my local file system that the web server is running on with uuid file names

c7d43358-7532-4812-b828-b10b26694f0f.pdf

but I know "security through obscurity" is not the right solution ...

I want to restrict access to they files on a per account basis if possible. One thing I think I could do is upload them to S3 and provide a signed URL, but I want to avoid that for now if possible.

I am using Nginx/Django/Gunicorn/EC2/S3

What are some other solutions?

Gammadion answered 21/3, 2012 at 18:25 Comment(1)
For me django-private-storage have done the magic.Aiguille
T
3

How about enforcing user==owner at the view level, preventing access to the files, storing them as FileFields, and only retrieving the file if that condition is met.

e.g. You could use the @login_required decorator on the view to allow access only if logged in. This could be refined using request.user to check against the owner of the file. The User Auth section of the Django documentation is likely to be helpful here.

The other option, as you mention is via S3 itself, generating urls within Django which have a querystring allowing an authenticated user access to download a particular s3 object with a time limit. Details on that can be found at the s3 documentation. A similar question has been asked before here on SO.

Tiflis answered 21/3, 2012 at 18:53 Comment(0)
E
10

If you are serving small files, you can indeed use Django to serve them directly, writing the file into the HttpResponse object.

If you're serving large files however, you might want to leave that task to your webserver, you can use the X-Accel-Redirect header on Nginx (and X-Sendfile for Apache & Lighttpd) to have your webserver serve the file for you.

You can find more information about the header itself in Nginx's documentation here, and you could find some inspiration as to how to use that in Django here.

Once you're done sending files through Django views, enforcing user authentication should be pretty straightfoward using Django's auth framework.

Etam answered 21/3, 2012 at 18:59 Comment(0)
T
3

How about enforcing user==owner at the view level, preventing access to the files, storing them as FileFields, and only retrieving the file if that condition is met.

e.g. You could use the @login_required decorator on the view to allow access only if logged in. This could be refined using request.user to check against the owner of the file. The User Auth section of the Django documentation is likely to be helpful here.

The other option, as you mention is via S3 itself, generating urls within Django which have a querystring allowing an authenticated user access to download a particular s3 object with a time limit. Details on that can be found at the s3 documentation. A similar question has been asked before here on SO.

Tiflis answered 21/3, 2012 at 18:53 Comment(0)
O
2

I've used django-private-files with great success, it enforces protection at the view level and uses differente backends to do the actual file transfer.

Orangeade answered 21/3, 2012 at 18:58 Comment(0)
E
-2

To manage user access to static files in a Django application when serving the files with Nginx, you can implement a secure system to control access. Here’s a step-by-step approach to solve this problem:

  1. Protect the Static Files with Nginx

First, configure Nginx to restrict direct access to the static files. This can be done by using internal redirects and access control in Nginx.

Edit your Nginx configuration file (e.g., /etc/nginx/sites-available/your_site):

nginx

server {
    listen 80;
    server_name your_domain.com;

    location /static/ {
        internal;
        alias /path/to/staticfiles/;
    }

    location /media/ {
        internal;
        alias /path/to/mediafiles/;
    }

    location /protected_static/ {
        alias /path/to/staticfiles/;
        add_header X-Accel-Redirect /static/;
    }

    location /protected_media/ {
        alias /path/to/mediafiles/;
        add_header X-Accel-Redirect /media/;
    }

    location / {
        proxy_pass http://127.0.0.1:8000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

In this configuration:

/static/ and /media/ locations are marked as internal, meaning they cannot be accessed directly from the outside. The /protected_static/ and /protected_media/ locations act as a proxy to these internal locations, adding an X-Accel-Redirect header to perform an internal redirect.

  1. Secure URLs with Django

In Django, create a view that checks user permissions before serving the static files. This view will generate URLs that Nginx can handle.

from django.http import HttpResponse, Http404
from django.conf import settings
import os

def serve_protected_file(request, file_path):
    # Check user permissions here
    if not request.user.is_authenticated:
        raise Http404

    # Generate the X-Accel-Redirect header
    response = HttpResponse()
    response['Content-Disposition'] = 'attachment; filename="%s"' % os.path.basename(file_path)
    response['X-Accel-Redirect'] = os.path.join('/protected_static/', file_path)
    response['Content-Type'] = ''

    return response
  1. Update URLs

Update your urls.py to point to the new view:

from django.urls import path
from . import views

urlpatterns = [
    path('protected_static/<path:file_path>/', views.serve_protected_file, name='serve_protected_file'),
]
  1. Use the Secure URLs in Templates

In your templates, use the secure URLs:

<a href="{% url 'serve_protected_file' file_path='path/to/your/file.jpg' %}">Download</a>
  1. Additional Security Measures

    Token-based access: For added security, generate temporary access tokens that expire after a certain period. Logging and monitoring: Log access to protected files and monitor for unusual activity.

Following these steps ensures that static files are protected and only accessible to authorized users. The combination of Nginx's internal redirects and Django's permission checks allows you to manage user access to URLs securely.

Essy answered 2/7, 2024 at 11:44 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.