Skip to content
Permalink
Browse files

[1.7.x] Prevented views.static.serve() from using large memory on lar…

…ge files.

This is a security fix. Disclosure following shortly.
  • Loading branch information...
timgraham committed Dec 9, 2014
1 parent de67ded commit 818e59a3f0fbadf6c447754d202d88df025f8f2a
@@ -17,6 +17,8 @@
from django.utils.six.moves.urllib.parse import unquote
from django.utils.translation import ugettext as _, ugettext_lazy

STREAM_CHUNK_SIZE = 4096


def serve(request, path, document_root=None, show_indexes=False):
"""
@@ -61,7 +63,8 @@ def serve(request, path, document_root=None, show_indexes=False):
return HttpResponseNotModified()
content_type, encoding = mimetypes.guess_type(fullpath)
content_type = content_type or 'application/octet-stream'
response = StreamingHttpResponse(open(fullpath, 'rb'),
f = open(fullpath, 'rb')
response = StreamingHttpResponse(iter(lambda: f.read(STREAM_CHUNK_SIZE), b''),
content_type=content_type)
response["Last-Modified"] = http_date(statobj.st_mtime)
if stat.S_ISREG(statobj.st_mode):
@@ -45,6 +45,21 @@ from a XSS attack. This bug doesn't affect Django currently, since we only put
this URL into the ``Location`` response header and browsers seem to ignore
JavaScript there.

Denial-of-service attack against ``django.views.static.serve``
==============================================================

In older versions of Django, the :func:`django.views.static.serve` view read
the files it served one line at a time. Therefore, a big file with no newlines
would result in memory usage equal to the size of that file. An attacker could
exploit this and launch a denial-of-service attack by simultaneously requesting
many large files. This view now reads the file in chunks to prevent large
memory usage.

Note, however, that this view has always carried a warning that it is not
hardened for production use and should be used only as a development aid. Now
may be a good time to audit your project and serve your files in production
using a real front-end web server if you are not doing so.

Bugfixes
========

@@ -43,3 +43,18 @@ provide safe redirect targets and put such a URL into a link, they could suffer
from a XSS attack. This bug doesn't affect Django currently, since we only put
this URL into the ``Location`` response header and browsers seem to ignore
JavaScript there.

Denial-of-service attack against ``django.views.static.serve``
==============================================================

In older versions of Django, the :func:`django.views.static.serve` view read
the files it served one line at a time. Therefore, a big file with no newlines
would result in memory usage equal to the size of that file. An attacker could
exploit this and launch a denial-of-service attack by simultaneously requesting
many large files. This view now reads the file in chunks to prevent large
memory usage.

Note, however, that this view has always carried a warning that it is not
hardened for production use and should be used only as a development aid. Now
may be a good time to audit your project and serve your files in production
using a real front-end web server if you are not doing so.
@@ -44,6 +44,21 @@ from a XSS attack. This bug doesn't affect Django currently, since we only put
this URL into the ``Location`` response header and browsers seem to ignore
JavaScript there.

Denial-of-service attack against ``django.views.static.serve``
==============================================================

In older versions of Django, the :func:`django.views.static.serve` view read
the files it served one line at a time. Therefore, a big file with no newlines
would result in memory usage equal to the size of that file. An attacker could
exploit this and launch a denial-of-service attack by simultaneously requesting
many large files. This view now reads the file in chunks to prevent large
memory usage.

Note, however, that this view has always carried a warning that it is not
hardened for production use and should be used only as a development aid. Now
may be a good time to audit your project and serve your files in production
using a real front-end web server if you are not doing so.

Bugfixes
========

@@ -0,0 +1 @@
lorem ipsum dolor sit amet consectetur adipisicing elit sed do eiusmod tempor incididunt ut labore et dolore magna aliqua hic tempora est veritatis culpa fugiat doloribus fugit in sed harum veniam porro eveniet maxime labore assumenda non illum possimus aut vero laudantium cum magni numquam dolorem explicabo quidem quasi nesciunt ipsum deleniti facilis neque similique nisi ad magnam accusamus quae provident dolor ab atque modi laboriosam fuga suscipit ea beatae ipsam consequatur saepe dolore nulla error quo iusto expedita nemo commodi aspernatur aliquam enim reiciendis rerum necessitatibus recusandae sint amet placeat temporibus autem iste deserunt esse dolores reprehenderit doloremque pariatur velit maiores repellat dignissimos asperiores aperiam alias a corporis id praesentium voluptatibus soluta voluptatem sit molestiae quas odio facere nostrum laborum incidunt eaque nihil ullam rem mollitia at cumque iure tenetur tempore totam repudiandae quisquam quod architecto officia vitae consectetur cupiditate molestias delectus voluptates earum et impedit quibusdam odit sequi perferendis eius perspiciatis eos quam quaerat officiis sunt ratione consequuntur quia quis obcaecati repellendus exercitationem vel minima libero blanditiis eligendi minus dicta voluptas excepturi nam eum inventore voluptatum ducimus sapiente dolorum itaque ipsa qui omnis debitis voluptate quos aliquid accusantium ex illo corrupti ut adipisci natus animi distinctio optio nobis unde similique excepturi vero culpa molestias fugit dolorum non amet iure inventore nihil suscipit explicabo veritatis officiis distinctio nesciunt saepe incidunt reprehenderit porro vitae cumque alias ut deleniti expedita ratione odio magnam eligendi a nostrum laborum minus esse sit libero quaerat qui id illo voluptates soluta neque odit dolore consectetur ducimus nulla est nisi impedit quia sapiente ullam temporibus ipsam repudiandae delectus fugiat blanditiis maxime voluptatibus aspernatur ea ipsum quisquam sunt eius ipsa accusantium enim corporis earum sed sequi dicta accusamus dignissimos illum pariatur quos aut reiciendis obcaecati perspiciatis consequuntur nam modi praesentium cum repellat possimus iste atque quidem architecto recusandae harum eaque sint quae optio voluptate quod quasi beatae magni necessitatibus facilis aperiam repellendus nemo aliquam et quibusdam debitis itaque cupiditate laboriosam unde tempora commodi laudantium in placeat ad vel maiores aliquid hic tempore provident quas officia adipisci rem corrupti iusto natus eum rerum at ex quam eveniet totam dolor assumenda error eos doloribus labore fuga facere deserunt ab dolores consequatur veniam animi exercitationem asperiores mollitia minima numquam voluptatem voluptatum nobis molestiae voluptas omnis velit quis quo tenetur perferendis autem dolorem doloremque sequi vitae laudantium magnam quae adipisci expedita doloribus minus perferendis vero animi at quos iure facere nihil veritatis consectetur similique porro tenetur nobis fugiat quo ducimus qui soluta maxime placeat error sunt ullam quaerat provident eos minima ab harum ratione inventore unde sint dolorum deserunt veniam laborum quasi suscipit facilis eveniet voluptatibus est ipsum sapiente omnis vel repellat perspiciatis illo voluptate aliquid magni alias modi odit ea a voluptatem reiciendis recusandae mollitia eius distinctio amet atque voluptates obcaecati deleniti eligendi commodi debitis dolore laboriosam nam illum pariatur earum exercitationem velit in quas explicabo fugit asperiores itaque quam sit dolorem beatae quod cumque necessitatibus tempora dolores hic aperiam ex tempore ut neque maiores ad dicta voluptatum eum officia assumenda reprehenderit nisi cum molestiae et iusto quidem consequuntur repellendus saepe corrupti numquam culpa rerum incidunt dolor impedit iste sed non praesentium ipsam consequatur eaque possimus quia quibusdam excepturi aspernatur voluptas quisquam autem molestias aliquam corporis delectus nostrum labore nesciunt blanditiis quis enim accusamus nulla architecto fuga natus ipsa repudiandae cupiditate temporibus aut libero optio id officiis esse dignissimos odio totam doloremque accusantium nemo rem repudiandae aliquam accusamus autem minima reiciendis debitis quis ut ducimus quas dolore ratione neque velit repellat natus est error ea nam consequuntur rerum excepturi aspernatur quaerat cumque voluptatibus rem quasi eos unde architecto animi sunt veritatis delectus nulla at iusto repellendus dolorum obcaecati commodi earum assumenda quisquam cum officiis modi ab tempora harum vitae voluptatem explicabo alias maxime nostrum iure consectetur incidunt laudantium distinctio deleniti iste facere fugit libero illo nobis expedita perferendis labore similique beatae sint dicta dignissimos sapiente dolor soluta perspiciatis aut ad illum facilis totam necessitatibus eveniet temporibus reprehenderit quidem fugiat magni dolorem doloribus quibusdam eligendi fuga quae recusandae eum amet dolores asperiores voluptas inventore officia sit vel id vero nihil optio nisi magnam deserunt odit corrupti adipisci aliquid odio enim pariatur cupiditate suscipit voluptatum corporis porro mollitia eaque quia non quod consequatur ipsa nesciunt itaque exercitationem molestias molestiae atque in numquam quo ipsam nemo ex tempore ipsum saepe esse sed veniam a voluptates placeat accusantium quos laboriosam voluptate provident hic sequi quam doloremque eius impedit omnis possimus laborum tenetur praesentium et minus ullam blanditiis culpa qui aperiam maiores quidem numquam nulla
@@ -8,7 +8,7 @@
from django.http import HttpResponseNotModified
from django.test import SimpleTestCase, override_settings
from django.utils.http import http_date
from django.views.static import was_modified_since
from django.views.static import was_modified_since, STREAM_CHUNK_SIZE

from .. import urls
from ..urls import media_dir
@@ -33,6 +33,14 @@ def test_serve(self):
self.assertEqual(len(response_content), int(response['Content-Length']))
self.assertEqual(mimetypes.guess_type(file_path)[1], response.get('Content-Encoding', None))

def test_chunked(self):
"The static view should stream files in chunks to avoid large memory usage"
response = self.client.get('/%s/%s' % (self.prefix, 'long-line.txt'))
first_chunk = next(response.streaming_content)
self.assertEqual(len(first_chunk), STREAM_CHUNK_SIZE)
second_chunk = next(response.streaming_content)
self.assertEqual(len(second_chunk), 1451)

def test_unknown_mime_type(self):
response = self.client.get('/%s/file.unknown' % self.prefix)
self.assertEqual('application/octet-stream', response['Content-Type'])

0 comments on commit 818e59a

Please sign in to comment.
You can’t perform that action at this time.