I have multiple FileFields in my django app, which can belong to different users. I am looking for a good way to restrict access to files for user who aren't the owner of the file.
What is the best way to achieve this? Any ideas?
I have multiple FileFields in my django app, which can belong to different users. I am looking for a good way to restrict access to files for user who aren't the owner of the file.
What is the best way to achieve this? Any ideas?
Unfortuanately @Mikko's solution cannot actually work on a production environment since django is not designed to serve files. In a production environment files need to be served by your HTTP server (e.g apache, nginx etc) and not by your application/django server (e.g uwsgi, gunicorn, mod_wsgi etc).
That's why restricting file acccess is not very easy: You need a way for your HTTP server to ask the application server if it is ok to serve a file to a specific user requesting it. As you can understand thiss requires modification to both your application and your http server.
The best solution to the above problem is django-sendfile (https://github.com/johnsensible/django-sendfile) which uses the X-SendFile mechanism to implement the above. I'm copying from the project's description:
To understand more about the senfile mechanism, please read this answer: Django - Understanding X-Sendfile
2018 Update: Please notice that django-sendfile does not seem to be maintained anymore; probably it should still be working however if you want a more modern package with similar functionality take a look at https://github.com/edoburu/django-private-storage as commenter @surfer190 proposes. Especially make sure that you implement the "Optimizing large file transfers" section; you actuallyu need this for all transfers not only for large files.
Generally, you do not route private files through normal static file serving directly through Apache, Nginx or whatever web server you are using. Instead write a custom Django view which handles the permission checking and then returns the file as streaming download.
Make sure files are in a special private folder folder and not exposed through Django's
MEDIA_URL
orSTATIC_URL
Write a view which will
Check that the user has access to the file in your view logic
Open the file with Python's
open()
Return HTTP response which gets the file's handle as the parameter
http.HttpResponse(_file, content_type="text/plain")
For example see
download()
here.If you need just moderate security, my approach would be the following:
1) When the user uploads the file, generate a hard to guess path for it. For example you can create a folder with a randomly generated name for each uploaded file in your /static folder. You can do this pretty simply using this sample code:
In this way it will be very hard to guess where other users' files are stored.
2) In the database link the owner to the file. An example schema can be:
uploads(id, user_id, file_path)
3) Use a property for your FileFields in the model to restrict access to the file, in this way:
This is best handled by the server, e.g. nginx secure link module (nginx must be compiled with
--with-http_secure_link_module
)Example from the documentation:
The file would be accessed like:
(This would be both time-limited and bound to the user at that IP address).
Generating the token to pass to the user would use something like: