Separate handling of protected media in Django, with X-Sendfile support

Overview

Build Status

Django Protected Media

Django Protected Media is a Django app that manages media that are considered sensitive in a protected fashion.

Not only does the media get stored in a separate filesystem location, but authorisation is also required to access it.

The application allows for setups where Django performs the authorisation, but hands off the serving of the file to a web server, like Nginx.

Quick start

  1. Add "protected_media" to your INSTALLED_APPS setting like this:
INSTALLED_APPS = [
    ...
    'protected_media.apps.ProtectedMediaConfig',
]
  1. Include the URLconf in your project urls.py like this::
path('protected/', include('protected_media.urls')),
  1. Add the following settings to settings.py if the defaults need to be tweaked:
PROTECTED_MEDIA_ROOT = "%s/protected/" % BASE_DIR
PROTECTED_MEDIA_URL = "/protected"
PROTECTED_MEDIA_SERVER = "nginx"  # Defaults to "django"
PROTECTED_MEDIA_LOCATION_PREFIX = "/internal"  # Prefix used in nginx config
PROTECTED_MEDIA_AS_DOWNLOADS = False  # Controls inclusion of a Content-Disposition header
  1. Use the new field classes in your models:
from protected_media.models import ProtectedImageField, ProtectedFileField

def SomeModel(models.Model):
    document = ProtectedFileField(upload_to="uploads/")
    picture = ProtectedImageField(upload_to="uploads/")
    # Files will be stored under PROTECTED_MEDIA_ROOT + upload_to

Overview

Django manages media based on the following definitions:

BASE_DIR = "/some/application/dir/"
MEDIA_ROOT = "%s/media/" % BASE_DIR
MEDIA_URL = "/media/"

File- and image fields are typically defined as:

document = models.FileField(upload_to="uploads/")
picture = models.ImageField(upload_to="uploads/")
# Files will be stored under MEDIA_ROOT + upload_to

In a typical production environment one would let nginx (or some other server) serve the media:

# Publicly accessible media
location ^~ /media/ {
    alias /some/application/dir/media
}

This works well when the media should be publically accessible. However, if the media should be protected, we need a way for Django to check whether the request for the media should only be allowed for logged in (or more stringent criteria) users.

The protected_media application

The protected_media application consists of

  • new settings.py attributes,
  • a customized FileSystemStorage class,
  • a custom handler for the protected media URL and
  • additional web server configuration if serving via nginx or something similar.

Protected media is stored in a different physical location to publically accessible media. The following settings can be specified in settings.py:

PROTECTED_MEDIA_ROOT = "/some/application/dir/protected/"
PROTECTED_MEDIA_URL = "/protected"
PROTECTED_MEDIA_SERVER = "nginx"  # Defaults to "django"
PROTECTED_MEDIA_LOCATION_PREFIX = "/internal"  # Prefix used in nginx config

When defining a file or image field that needs to be protected, we use one of the classes provided by the protected_media application:

  • ProtectedFileField
  • ProtectedImageField

Protected file- and image fields are typically defined as:

document = ProtectedFileField(upload_to="uploads/")
picture = ProtectedImageField(upload_to="uploads/")
# Files will be stored under PROTECTED_MEDIA_ROOT + upload_to

These classes have a custom storage backend ProtectedFileSystemStorage which mananges the filesystem location and URLs associated with protected media.

When nginx is used, the configuration must be updated to look like this:

# Publicly accessible media
location /media  {
    alias /some/application/dir/media;
}

# Protected media
location /internal  {
    internal;
    alias /some/application/dir/protected;
}
Comments
  • Improve README.md

    Improve README.md

    Hi @cobusc ,

    This PR fixs how we are adding into URLconf. Instead of django.conf.urls.url() lets show example with django.urls.path() - the new modern way. Also, url() will be deprecated in Django 4.0.

    Also, let's show adding AppConfig as dotted path as it is recommended at Django docs. Otherwise we should add default_app_config variable inside __init__.py file.

    opened by DmytroLitvinov 7
  • Outdated version on PyPI

    Outdated version on PyPI

    Hi, first of all I'd like to thank you for creating this package.

    I noticed a fix for Django 4 got merged in and version in setup.py was bumped to 1.0.1: https://github.com/cobusc/django-protected-media/blob/acb05009d65763ce5b6246729f1cc2368f44ae7e/setup.py#L12

    However, latest version on PyPI is still 1.0.0: https://pypi.org/project/django-protected-media/#history Is this intended?

    opened by IhateTrains 4
  • Update

    Update

    I wanted to get this into awesome Django but they feel this project is not kept up to date. Could you update it?

    Or say here that you welcome others updating the project? This way maybe someone submits a PR.

    opened by morenoh149 3
  • 'Settings' object has no attribute 'BASE_DIR'

    'Settings' object has no attribute 'BASE_DIR'

    BASE_DIR is not a mandatory entry in Django's settings.py. Thus, even though one defined PROTECTED_MEDIA_ROOT, an AttributeError exception will be thrown because of protected_media's own settings.py trying to define a default PROTECTED_MEDIA_ROOT using BASE_DIR.

    Protected-media's documentation doesn't make it clear BASE_DIR is required as it probably shouldn't be.

    opened by danilogbotelho 2
  • Migrate to new CI platform

    Migrate to new CI platform

    opened by johnthagen 1
  • Nginx showing 404 Not Found instead of protected media

    Nginx showing 404 Not Found instead of protected media

    I'm getting Nginx 404 Not Found instead of protected media which is image in my case. Kindly asking for a help because I don't understand what I am doing wrong.

    In settings.py I have this:

    PROTECTED_MEDIA_ROOT = os.path.join(BASE_DIR, 'protected')
    PROTECTED_MEDIA_URL = "/protected"
    PROTECTED_MEDIA_SERVER = "nginx"  # Defaults to "django"
    PROTECTED_MEDIA_LOCATION_PREFIX = "/internal" # Prefix used in nginx config
    PROTECTED_MEDIA_AS_DOWNLOADS = False  # Controls inclusion of a Content-Disposition header
    

    In django I have this:

    @login_required
    def my_media_access(request, media_object, file_relpath):
        # some code to check if access is granted
        if access_granted:
            return protected_view(request, file_relpath, server = PROTECTED_MEDIA_SERVER, as_download = PROTECTED_MEDIA_AS_DOWNLOADS)
        return HttpResponseForbidden('Not authorized to access this media.')
    

    In Nginx configuration I have:

        location /internal {
            internal;
            root /home/myuser/myproject/protected;
        }
    

    So the files are in folder /home/myuser/myproject/protected. Idea is that when you access URL https://example.com/protected/abc/image/4813-image1.png then Django recognizes this path and calls protected_view in django-protected-media.

    This are the test results for logged in user which is allowed to see asset:

    • opening https://example.com/protected/abc/image/4813-image1.png - 404 Not Found (nginx) which is NOT OK, image should be shown
    • opening https://example.com/internal/abc/image/4813-image1.png - 404 Not Found (nginx) which is OK
    • opening https://example.com/protected/abc/image/4813-image1_WRONG_PATH.png - Django message that there is no route which is OK
    opened by pitagora04 1
  • Missing '/' in PROTECTED_MEDIA_URL by default

    Missing '/' in PROTECTED_MEDIA_URL by default

    Hi,

    I found that '/' is missing for default PROTECTED_MEDIA_URL "/protected/". Otherwise, the URL displayed is not the correct one.

    The URL prefix used by protected media

    PROTECTED_MEDIA_URL = getattr( settings, "PROTECTED_MEDIA_URL", "protected/" )

    Alternatively, user has to define the settings by themselves. PROTECTED_MEDIA_URL = '/protected/'

    opened by aliceni81 1
  • CI updates and other tweaks

    CI updates and other tweaks

    What was done

    • Sorted out the Travis CI pipeline. Added newer versions of Python and Django.
    • Explicitly error when PROTECTED_MEDIA_ROOT is not explicitly defined and BASE_DIR (used to compute the default value) is also not defined.
    • Added missing trailing "/" in the default value for PROTECTED_MEDIA_URL
    opened by cobusc 0
Owner
Cobus Carstens
Cobus Carstens
A python script to decrypt media files encrypted using the Android application 'Decrypting 'LOCKED Secret Calculator Vault''. Will identify PIN / pattern.

A python script to decrypt media files encrypted using the Android application 'Decrypting 'LOCKED Secret Calculator Vault''. Will identify PIN / pattern.

null 3 Sep 26, 2022
Industry ready custom API payload with an easy format for building Python APIs (Django/Django Rest Framework)

Industry ready custom API payload with an easy format for building Python APIs (Django/Django Rest Framework) Yosh! If you are a django backend develo

Abram (^o^) 7 Sep 30, 2022
BoobSnail allows generating Excel 4.0 XLM macro. Its purpose is to support the RedTeam and BlueTeam in XLM macro generation.

Follow us on Twitter! BoobSnail BoobSnail allows generating XLM (Excel 4.0) macro. Its purpose is to support the RedTeam and BlueTeam in XLM macro gen

STM Cyber 232 Nov 21, 2022
HatSploit native powerful payload generation and shellcode injection tool that provides support for common platforms and architectures.

HatVenom HatSploit native powerful payload generation and shellcode injection tool that provides support for common platforms and architectures. Featu

EntySec 100 Dec 23, 2022
Docker Compose based system for running remote browsers (including Flash and Java support) connected to web archives

pywb Remote Browsers This repository provides a simple configuration for deploying any pywb with remote browsers provided by OWT/Shepherd Remote Brows

Webrecorder 10 Jul 28, 2022
Colin O'Flynn's Hacakday talk at Remoticon 2021 support repo.

Hardware Hacking Resources This repo holds some of the examples used in Colin's Hardware Hacking talk at Remoticon 2021. You can see the very sketchy

Colin O'Flynn 19 Sep 12, 2022
A dynamic multi-STL, multi-process OpenSCAD build system with autoplating support

scad-build This is a multi-STL OpenSCAD build system based around GNU make. It supports dynamic build targets, intelligent previews with user-defined

Jordan Mulcahey 1 Dec 21, 2021
Set the draft security HTTP header Permissions-Policy (previously Feature-Policy) on your Django app.

django-permissions-policy Set the draft security HTTP header Permissions-Policy (previously Feature-Policy) on your Django app. Requirements Python 3.

Adam Johnson 76 Nov 30, 2022
Red Team Toolkit is an Open-Source Django Offensive Web-App which is keeping the useful offensive tools used in the red-teaming together.

RedTeam Toolkit Note: Only legal activities should be conducted with this project. Red Team Toolkit is an Open-Source Django Offensive Web-App contain

Mohammadreza Sarayloo 382 Jan 1, 2023
A Udemy downloader that can download DRM protected videos and non-DRM protected videos.

Udemy Downloader with DRM support NOTE This program is WIP, the code is provided as-is and i am not held resposible for any legal repercussions result

Puyodead1 468 Dec 29, 2022
The simple project to separate mixed voice (2 clean voices) to 2 separate voices.

Speech Separation The simple project to separate mixed voice (2 clean voices) to 2 separate voices. Result Example (Clisk to hear the voices): mix ||

vuthede 31 Oct 30, 2022
Fully Automated YouTube Channel ▶️with Added Extra Features.

Fully Automated Youtube Channel ▒█▀▀█ █▀▀█ ▀▀█▀▀ ▀▀█▀▀ █░░█ █▀▀▄ █▀▀ █▀▀█ ▒█▀▀▄ █░░█ ░░█░░ ░▒█░░ █░░█ █▀▀▄ █▀▀ █▄▄▀ ▒█▄▄█ ▀▀▀▀ ░░▀░░ ░▒█░░ ░▀▀▀ ▀▀▀░

sam-sepiol 249 Jan 2, 2023
google-resumable-media Apache-2google-resumable-media (🥉28 · ⭐ 27) - Utilities for Google Media Downloads and Resumable.. Apache-2

google-resumable-media Utilities for Google Media Downloads and Resumable Uploads See the docs for examples and usage. Experimental asyncio Support Wh

Google APIs 36 Nov 22, 2022
django Filer is a file management application for django that makes handling of files and images a breeze.

django Filer is a file management application for django that makes handling of files and images a breeze.

django CMS Association 1.6k Jan 6, 2023
This is a Python library for accessing resources protected by OAuth 2.0.

This is a client library for accessing resources protected by OAuth 2.0. Note: oauth2client is now deprecated. No more features will be added to the l

Google APIs 787 Dec 13, 2022
Official implementation of Protected Attribute Suppression System, ICCV 2021

Official implementation of Protected Attribute Suppression System, ICCV 2021

Prithviraj Dhar 6 Jan 1, 2023
Create or join a private chatroom without any third-party middlemen in less than 30 seconds, available through an AES encrypted password protected link.

PY-CHAT Create or join a private chatroom without any third-party middlemen in less than 30 seconds, available through an AES encrypted password prote

null 1 Nov 24, 2021
Easy-to-use data handling for SQL data stores with support for implicit table creation, bulk loading, and transactions.

dataset: databases for lazy people In short, dataset makes reading and writing data in databases as simple as reading and writing JSON files. Read the

Friedrich Lindenberg 4.2k Dec 26, 2022
Easy-to-use data handling for SQL data stores with support for implicit table creation, bulk loading, and transactions.

dataset: databases for lazy people In short, dataset makes reading and writing data in databases as simple as reading and writing JSON files. Read the

Friedrich Lindenberg 4.2k Jan 2, 2023
Securetar - A streaming wrapper around python tarfile and allow secure handling files and support encryption

Secure Tar Secure Tarfile library It's a streaming wrapper around python tarfile

Pascal Vizeli 2 Dec 9, 2022