The official docs say, of the staticfiles serve view:
... this view is grossly inefficient and probably insecure
Does this warning apply only to this particular view, or are there security issues inherent in the concept of serving static files through Django? What are they? Assuming I've benchmarked my application and performance is acceptable, are there any other issues I should be aware of?
It's insecure because it doesn't have to be secure
Serving static files through django means you go through the Python code to do something your webserver would do significantly more efficiently.
Given that serving static files is disastrous performance-wise, no-one would use this in production.
Therefore, no-one cares about the security of serving static files in Django.
As a consequence, this view is probably insecure.
Ultimately, it's the same rationale as the development server. You're not supposed to be using it in production and not one is dedicating effort to making it secure. It's just practical for development.
Also, something inefficient is something that exposes you to DoS attacks. So yes, it's insecure.
But you shouldn't be using it.
Why are you serving static files through Django? Is it to control access to those files?
If yes, you should use the X-Accel-Redirect(Nginx) or X-Sendfile (Apache) headers.
But don't do it yourself, use: https://github.com/johnsensible/django-sendfile
Related
I've seen many questions on stackoverflow about handling static files in django during deployment. I saw that many answers said something like this - "With debug turned off Django won't handle static files for you any more - your production web server (Apache or something) should take care of that."
Why can't we use the server hosting the django project to host the static files too?
Static files don't require any kind of logic or processing. It is more efficient to deliver them directly to the end-user directly from disk via a web server, rather than running them through the middle layer of Django. That middle layer (such as gunicorn, uwsgi, or mod_wsgi) is what allows things like views to be processed and for the ORM to connect with a database. Since static files require none of that, bypassing it is the most efficient. The same is true for media files that are uploaded by the end user. Good luck!
This might be a stupid question and have an obvious answer, but I was testing my 404 and 500 error handlers meaning that I had to switch debug to False. I went to Django admin page and noticed that static files are not being served.
I understand that they should be routed through Apache as serving static files through Django is insecure. However, I don't quite understand why is it a security risk to serve static files through Django directly?
Here is what the Django 1.8 documentation says on the subject:
--insecure
Use the --insecure option to force serving of static files with the staticfiles app even if the DEBUG setting is False. By using this you acknowledge the fact that it’s grossly inefficient and probably insecure. This is only intended for local development, should never be used in production and is only available if the staticfiles app is in your project’s INSTALLED_APPS setting.
As you can see, they say "grossly inefficient" and "probably insecure". They didn't say "definitely insecure" or "insecure". I think that what they are hinting at is that they haven't done a thorough security analysis of the staticfiles app and its interactions with the rest of Django.
For me, the "grossly inefficient" part should be sufficient to deter you from serving static content. It is easy to do it better ... starting with the collectstatic command.
Some more searching lead me to this Google Groups posting, in response to someone asking about why --insecure is insecure.
From: Malcolm Tredinnick
Nothing can be considered secure unless it is designed and audited for
security. We have done neither with the static file server. It may not
have existing security holes, but it should not be considered secure
because that's not a design goal.
For example, a secure file server would need to check for resource
allocation problems so that serving a very large file didn't constitute
a denial-of-service attack. That requires a lot of extra code and
pipeline management which isn't worth putting into something that's just
for development purposes.
... which supports my interpretation.
This link:
https://docs.djangoproject.com/en/1.8/howto/static-files/ starts off by explaining a "grossly inefficient and probably insecure, unsuitable for production" way of serving files. It also explains how to use
django.contrib.staticfiles.views.serve()
which is "not suitable for production use!". I don't want to have to code an entire Django project, finish it and then end up having to change a lot of code right before deploying because the current code is "grossly inefficient and probably insecure, unsuitable for production".
With that said, what's the best approach (the approach which doesn't require a lot of extra work just to move my app from development to production) to take when serving static files? I'm asking because I've never been through the process of deploying a Django app before and when deploying, I don't want to end up saying to myself "wow, I should have done it that way rather than this way".
You don't change any code, because it's not your code that serves static files. You need to configure your web server to do it; which is fine, because you're configuring your web server anyway for deployment.
The whole point of the staticfiles app in Django is just that, that it manages files for you in development and puts them in a single place for deployment so you can point your web server at them.
As stated in: https://docs.djangoproject.com/en/dev/howto/static-files/
When DEBUG is set to True, the server automatically serves the static file, but it states:
This method is grossly inefficient and probably insecure, so it is unsuitable for production.
But what exactly is inefficient and insecure about it? I just have a small-ish project on Heroku that I haven't set to "production" mode yet and I'm wondering what are the exact downsides.
Performance related reasons:
web servers are orders of magnitude better at serving static files.
AFAIK the development server is mono-threaded and can respond only one request at time, concurrent requests will block (most browsers make 4 concurrent requests trying to download assets in parallel).
Security related reasons:
using the app to serve static content is overkill (simplification is good for security)
the developers like to be on the safe side, so it is kind of a disclaimer
debug mode exposes a lot of information about the server
Django started in the news publishing industry where in general there is enough traffic to justify serving static content from a dedicated web server, probably the original developers have a bias for this arrangement.
That said, there are projects that replace the default development server by a more robust implementation based on gunicorn or tornado.
Kenneth (the author of requests, employed by Heroku) has a different opinion (source):
In reality, serving static files through Python/Django is fine for
production — those requests are no different than dynamic ones.
Performance will be fantastic, but not as good as nginx.
If you're that heavily concerned about efficiency then you shouldn't
be hosting those files on your server anyway, you'd be pushing them to
an CDN like S3+Cloudfront and the like.
Another benefit to this approach is development:production parity.
And on heroku, you can't use Nginx to server static files, actually you can't do it on most other PaaS too, I got the same problem on cloud foundry last year. But there is a workaround:
On Heroku, your application directly responds to HTTP requests,
instead of going through an additional web server like Apache or
Nginx.
We recommend most applications serve their assets strait from Django
or a CDN.
Django doesn't recommend serving static files in production because of
the design of its static file handler.
Luckily, there is a library called DJ-Static which makes uses a
production-ready WSGI asset server.
I've written up a guide for Django and Static Assets here:
https://devcenter.heroku.com/articles/django-assets
Read the following discussions for more details:
Serving static files for a Django app
serving static files via gunicorn
I've searched around on this topic, and the advice seems to be that nginx should be there to serve static files and apache+wsgi for dealing with Django. A lot of this information is a couple of years old, so I was wondering if there was a way to simplify this without performance degradation and just rely on Nginx and fastCGI and/or wsgi.
I'm new to non-heroku deployment, so this is why I probably sound like I don't know what I'm talking about.
No you don't need Apache+wsgi along with Nginx+fCGI/wsgi. Nginx can serve static files really fast and it will use fCGI/wsgi for rest of the requests.
You should read answer to this questions[1] and other related questions mentioned there.
[1]. What is the disadvantage of using Django's fastcgi server
If you want to go the nginx route, the best choices are:
nginx -> gunicorn
nginx -> uWSGI
Running Python WSGI applications on top of FASTCGI is not generally as good an experience due to issues with the FASTCGI/WSGI adapters and how they are deployed with servers.
Apache/mod_wsgi is still a more than acceptable solution and it will actually perform better with less resources when run as:
nginx -> Apache/mod_wsgi
Because the bottlenecks aren't going to be the web server, ultimately it doesn't matter which you choose, so long as you set it up properly, something which most people wouldn't do as there site doesn't get enough traffic anyway, or they have no monitoring in place to know what they need to change.
Overall, picking which you think is easier to manage is the best thing to do when starting out.
For some background on what your real performance bottlenecks are going to be and the importance of monitoring, watch:
http://lanyrd.com/2012/pycon/spcdg/
That all said, you mention Heroku. Right now there is really only the once choice with Heroku and that is to use gunicorn and you wouldn't need to be worrying about nginx. That is a problem in itself though, as gunicorn alone is not a good option for serving static media assets so almost forced with Heroku to serve static assests elsewhere.