Django - Understanding X-Sendfile
Asked Answered
T

1

38

I've been doing some research regarding file downloads with access control, using Django. My goal is to completely block access to a file, except when accessed by a specific user. I've read that when using Django, X-Sendfile is one of the methods of choice for achieving this (based on other SO questions, etc). My rudimentary understanding of using X-Sendfile with Django is:

  1. User requests URI to get a protected file
  2. Django app decides which file to return based on URL, and checks user permission, etc.
  3. Django app returns an HTTP Response with the 'X-Sendfile' header set to the server's file path
  4. The web server finds the file and returns it to the requester (I assume the webs server also strips out the 'X-Sendfile' header along the way)

Compared with chucking the file directly from Django, X-Sendfile seems likely to be a more efficient method of achieving protected downloads (since I can rely on Nginx to serve files, vs Django), but leaves 2 questions for me:

  1. Is my explanation of X-Sendfile at least abstractly correct?
  2. Is it really secure, assuming I don't provide normal, front-end HTTP access (e.g. http://www.example.com/downloads/secret-file.jpg) to the directory that the file is stored (ie, don't keep it in my public_html directory)? Or, could a tech-savvy user examine headers, etc. and reverse engineer a way to access a file (to then distribute)?
  3. Is it really a big difference in performance. Am I going to bog my application server down by providing 8b chunked downloads of 150Mb files directly from Django, or is this sort-of a non-issue? The reason I ask is because if both versions are near equal, the Django version would be preferable due to my ability to do things in Python, like log the number of completed downloads, tally bandwidth of downloads etc.

Thanks in advance.

Trinitrotoluene answered 4/9, 2011 at 0:20 Comment(4)
in the steps you outlined above, one thing is not clear to me: when you said Django app returns an HTTP response with the X-Sendfile header set, who is the recipient of that response? I guess it will be the web server (e.g. nginx). If that is the case, who initiated the request that is handled by the Django app in the first place?Alarum
@Alarum - the user (web browser) - basically, you'd want to set up a view like get_file(request, file_name) (something to that effect) and when a user visits the URL, return a response with X-Sendfile pointing to the correct location for the named file (after adding whatever logic you want in the view to determine whether the user should be allowed to download the file). Nginx will intercept the response on its way out and return a response with the file (as a download).Trinitrotoluene
so nginx must be set up in front of the Django app server then? Otherwise, how can nginx intercept the response on its way out?Alarum
@Alarum - that's correct. For instance, you can use Nginx to serve your static files (CSS, etc.) for your site, and also use it as a "reverse proxy" which passes the request to your application server (e.g., uWSGI), which in turn runs your Django app and gets a response, then returns it to Nginx, which decides what to do (e.g., return the response, or serve a download in the case of X-Sendfile, etc.)Trinitrotoluene
S
27
  1. Yes, that's just how it works.
  2. The exact implementation depends on the webserver but in the case of nginx, it's recommended to mark the location as internal to prevent external access.
  3. Nginx can asynchronously serve files while with Django you need one thread per request which can get problematic for higher numbers of parallel requests.

Remember to send a X-Accel-Redirect header for nginx instead of X-Sendfile. See http://wiki.nginx.org/XSendfile for more information.

Sublimation answered 4/9, 2011 at 3:47 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.