Serving uploaded images securely in Django? - django

My Django site lets users upload images. It's running on Apache.
Files are uploaded via a FileUpload form. The folder to which files are uploaded is outside the Django project, and protected as described here, i.e. the folder has 755 permissions and files have 644 permissions.
I now want to serve the images up to users - but I need to do it securely, so that executable scripts don't run, and so that users can't e.g. delete all the images in the directory.
My question is, how do I serve the uploaded images to users in a secure way? Can I serve them safely as static media directly from that folder, with those permissions? Or should I copy them into another directory with different permissions, and serve them from there?
I'm serving the other static media (/media/css) on the site as a separate, static application.
Thanks!

The way to do this is to configure your web server to serve files with the names it expects, and with a correct image content-type. Use Django's ImageField for some level of validation by PIL/Pillow that uploaded files are images. For this directory, disable webserver features like autogenerating directory indexes, autoserving everything from the filesystem, guessing at mime types, and running cgi scripts.

Related

I want to serve static files with permissions logic in my django project

So I've been working on a django project. Its a marketplace platform (two kinds of users - buyer & seller) and when a seller uploads files for a buyer, only those two users should have access to the uploaded files. I'm trying to figure how static files can be served with these permissions.
I'm not sure if this is relevant but I'm using nginx to serve the static files, so is there a way to add permissions logic in django to serve these static files?
A bit of Django terminology first: you're not talking about "static files" (those are the css, js, images and other assets that are part of your source) but about "media files" (user uploaded content).
Now for the technical answer: use nginx's X-Accel-Redirect feature. This delegates the permissions validation to your Django app, but still let nginx serve the file itself.

django cms filer uploads fail

[Update]
I've managed to upload a small file (but not yet a large image). ../media/filer_public/ sub-directories are being correctly created and file correctly uploaded. Need to investigate nginx configurations.
[OP]
I've logged into a new Django CMS system as superuser but cannot Add filer image or Add filer file to a page as the file upload silently fails; very briefly flashing its upload graphics but not actually uploading anything. I believe all the settings.py are correct as static artifacts are rendered correctly and Nginx has credible similar locations for both media and static directories.
I believe all file and directory permissions and ownerships are correct; i.e. that Nginx has user and / or group ownership of the Django CMS app directories and that permissions are correct.
The Postgres table filer_folder has a row for a new filer folder I created when editing a page but no corresponding directory has been created in the file system. I can add text and new text block plugins that get saved correctly.
Django CMS is running in a Docker container web which I have confirmed has rw (read/write) access to a Docker volume.
I see nothing abnormal in webs logs.
How can I find out what's (not) happening?
Simply adding client_max_body_size 10M; to the nginx configuration for the site solved the issue.
Similar issues were addressed in Stackoverflow and elsewhere:
Server Fault
Setting up Django and your web server with uWSGI and nginx

Push media files to a seperate nginx VM with Django in production

I don't know if I missed information regarding this. But I want to know how to store static files to a different VM. I've read that some recommend doing that to larger sites to seperate the load.
My current setup is that I use one computer engine with nginx, virtualenv, gunicorn etc. I use nginx to display the static files (including the media files) on the same server.
How can I push media files to a seperate nginx server when a user uploads an image? How can I obtain the same url as well?
Let's first explore the options of static resources(Javascript, CSS, Images, Fonts etc...)
You have complete control of where this static content should go during the deployment. Typically these resources will go for compression during the build process to optimize the content size to reduce the bandwidth.
Deploy the static resource on the different server(VM with ngnix) and configure that URL in the Django settings.py with STATIC_URL. If you use the cookieless domain, it will save little more bandwidth. Refer the section Use Cookie-free Domains for Components in this URL: https://developer.yahoo.com/performance/rules.html
You can use the content expiry settings for these resources to cache on the client for the specified duration.
Some best practices are mentioned in the official documentation: https://docs.djangoproject.com/en/1.10/howto/static-files/
For the media resources, you can save the files on the shared volume and run it on the different server same as static resources. You can configure that server URL in the Django settings.py with MEDIA_URL.

Non-public image upload

By default, Django uploads images to the MEDIA_ROOT setting, which is assumed to be a publicly accessible directory.
I don't want users to be able to upload images and to have those images immediately accessible. Instead, I want the images to be uploaded to a non-public tmp directory. Later on, a site moderator will approve images in django-admin, which will move them to a public image directory.
The catch is that the site moderators need to be able to view the images stored in the tmp directory in order to approve them. So, those images need to be served from the web server, but can't be accessible to users who aren't moderators.
How do I:
Extend ImageField to store images in a directory other than MEDIA_ROOT
Protect temporary images so that they are only viewable by site moderators before they are approved?
Re 2: completely protecting them on django level is impossible, since static media is served by the webserver, bypassing django entirely.
What you could do instead, is to create a directory /private/ in your media source and protect it using normal apache means - eg .htaccess;
Though hash, which was suggested earlier, seems like a better method to me.

Django and Serving Static Files

I'm hosting a site on WebFaction using Django/mod_python/Python2.5. I've recently run into the concept of static files (when setting up my Django admin).
From what I understand, serving static files is simply the idea of telling the server to serve files directly from a specific directory, rather than first routing the request through apache, then mod_python, then django, and finally back to the user. In the case of WebFaction this helps especially since there are two Apache servers that your request must go through (your app's server and the main public server).
Why is it that when I setup Django's static files, it only needs the /media folder in /contrib/admin? Is it just that all of Django's static content is related to the admin panel?
When I want to serve my own static content (images, css, etc.) should I include it in the same /media folder or set up another alias for my own content (/my_media)?
Yes, the static files used by Django are pretty much related to images, javascript and css for the admin. All other static content comes from your application. You can keep both sets (yours and the admin) under the same server. Just set the appropriate folders in the settings file.
http://docs.djangoproject.com/en/dev/ref/settings/#admin-media-prefix
http://docs.djangoproject.com/en/dev/ref/settings/#media-root
http://docs.djangoproject.com/en/dev/ref/settings/#media-url
See this post for a little more information:
Django and Static Files
Django's static files (e.g. js, css, images, etc.) are all in the media folder, and are related to the admin panel.
On WebFaction to save processing power, and more importantly memory, it is better to serve these from your secondary apache server (or even better from nginx or lighttpd) without having to go through mod_python and Django.
I use the following folder setup for my files:
media
css
js
img
etc
admin
css
js
img
See http://forum.webfaction.com/viewtopic.php?id=1981 for how to setup nginx as your secondary server on WebFaction if you are interested.