Non-public image upload - django

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.

Related

How to do URL masking with Django?

On a Django 1.9 project I need to redirect:
https://example.com/app/
to
https://examplebucket.s3.amazonaws.com/app/index.html
But I need https://examplce.com/app/ to be still visible on the browser address bar...
I know this must be possible in theory with Django because the previous team working on this project did a setup to serve the /static/ media files from an S3 bucket. And if I access those static files via https://example.com/static/app/index.html, they are served from the S3 bucket but the browser address bar still shows the original url I input.
I'm deploying an Ionic Browser project and I want the files (including the index) to be served from the S3 but the url needs to be user friendly, thats the reason.
The old (dirty) way of doing this is frame-based forwarding.
You set up an iframe on a page in /app/ which points at the real app, letting the url stay the same.
It's not considered a good practice because of security issues (can't be sure where you are typing credentials into), and bookmarking issues (url is always the same so can't bookmark inner pages).
Another alternative is to set up a proxy script that just takes the url, turns that into the equivalent aws url, downloads it and then returns it. This would break the benefits of your cloud hosting if it has multiple regions... it would always be passed through the bottleneck of your server.

AWS / Django - do I save private user uploaded files to S3 or on my EC2 instance?

I have a Django web application which allows users to upload their display picture. Some users can see this display picture but not everyone (not all users) should have access to this picture. With that said, in development, I used to save it locally on my machine. In my settings file, I had
MEDIA_ROOT = '/home/myProfile/Documents/thisFolder/uPhotosFolder'
MEDIA_URL = '/media/'
and Django would save all user uploaded display pictures to media rood (the uPhotosFolder) which was located on my machine.
With that said, I deployed (or at least am trying to deploy) the app and when I left my MEDIA_ROOT and MEDIA_URL in my settings file as
MEDIA_ROOT = '/home/myProfile/Documents/thisFolder/uPhotosFolder'
MEDIA_URL = '/media/'
and tried uploading an image, it said access was denied. Apparently I have to go into my EC2 instance (I use Amazon Web Services) and create the
'/home/myProfile/Documents/thisFolder/uPhotosFolder'
directory and then start saving the display images.
My question is, is this the correct / best way to save private user uploaded images on the server? Or should I use S3 for this as well? (From what I read, images on S3 are stored on the cloud and can be accessed from a URL by anyone) Is there a way to use S3 for my situation right now?
The question whether you store the image on EC2 instance in a folder or on S3 Storage is independent of the file privacy.
The MEDIA_ROOT defines the location of Media Folder. The MEDIA_URL defines the URL formed when serving media.
Now for storing if we use default file system storage we end up saving file in MEDIA_ROOT. We can change the storage to S3 by some additional configuration in settings file. ( Docs Here )
Now securing your files on user basis can be done by restricting access to URLs. For this Media URLs can be protected using X-Accell-Redirect headers use when using nginx to serve files.( eg: Here ).
In case you go ahead and use the S3 storage for serving media files ( more preferable in production environment ) - The S3 storage provides functions to get a protected URL for media which can be passed to client to retrieve media. These urls have accessibility for limited time period.

django internal file sharing with privacy

I am trying to write a job board / application system and I need the ability for clients to upload a CV and then share it with employers but I can't figure out the best way to do this. The CV needs to be kept private except for who it is shared with and there needs to be the ability for clients to update the cv after submitting it to an employer.
Is there a django app that does this already, or how would I go about setting up the privacy, file sharing etc so that the files can be copied and still private to just those shared with?
Use Apache's x-sendfile, for an example see: Having Django serve downloadable files
Store the files in a private folder. Django authorizes the request and let Apache serve the file using the x-sendfile header.
Use S3, and django-storages.
Upload the CV to S3, with the file set as private.
Create a view which will fetch a given CV from the S3 bucket, producing an "expiring URL", or that will just fetch the raw data from S3 and pass it through to the user through a view.
The file's privacy is completely controlled this way.
You could also do this by storing the uploaded file outside of your projects STATICs directory (which is assumed to be publicly accessible), and doing step 3 for that.
Or, if you want to make a DBA's head explode, store the CV as a BLOB in the database and use a view in the same way.

How to change django FileFiled 'storage' AFTER uploading?

I am developing two web sites using the Django framework.
The thing is - one site is sharing part of the content from the other one.
They both use different amazon WS buckets to store images, etc.
So for the site which shares some content with another one I need to specify a different MEDIA_URL, but it seems impossible cause 'upload_to' and 'storage' parameters of the FileField only influence the file being uploaded.
Is there any way to use another storage when displaying image after it was uploaded?

Serving uploaded images securely in 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.