On 28 August 2010 23:09, dave b <db.pub.m...@gmail.com> wrote: > On 28 August 2010 22:46, Graham Dumpleton <graham.dumple...@gmail.com> wrote: >> >> >> On Aug 28, 7:58 pm, "david b." <db.pub.m...@gmail.com> wrote: >>> Ok so I was looking through the code and I saw this (in >>> django/core/files/uploadhandler.py) : >>> >>> FileUploadHandler >>> ... >>> >>> def new_file(self, field_name, file_name, content_type, >>> content_length, charset=None): >>> """ >>> Signal that a new file has been started. >>> >>> Warning: As with any data from the client, you should not trust >>> content_length (and sometimes won't even get it). >>> """ >>> >>> So the content_length we control right? - Maybe I missed something but >>> ... I can say I want to upload a small file then upload a file that >>> triggers an oom condition / use a lot of memory no ? ... >>> >>> And then this. >>> >>> class MemoryFileUploadHandler(FileUploadHandler): >>> """ >>> File upload handler to stream uploads into memory (used for small >>> files). >>> """ >>> >>> def handle_raw_input(self, input_data, META, content_length, >>> boundary, encoding=None): >>> """ >>> Use the content_length to signal whether or not this handler >>> should be in use. >>> """ >>> # Check the content-length header to see if we should >>> # If the post is too large, we cannot use the Memory handler. >>> if content_length > settings.FILE_UPLOAD_MAX_MEMORY_SIZE: >>> self.activated = False >>> else: >>> self.activated = True >>> >>> def new_file(self, *args, **kwargs): >>> super(MemoryFileUploadHandler, self).new_file(*args, **kwargs) >>> if self.activated: >>> self.file = StringIO() >>> raise StopFutureHandlers() >>> >>> def receive_data_chunk(self, raw_data, start): >>> """ >>> Add the data to the StringIO file. >>> """ >>> if self.activated: >>> self.file.write(raw_data) >>> else: >>> return raw_data >>> >>> def file_complete(self, file_size): >>> """ >>> Return a file object if we're activated. >>> """ >>> if not self.activated: >>> return >>> >>> self.file.seek(0) >>> return InMemoryUploadedFile( >>> file = self.file, >>> field_name = self.field_name, >>> name = self.file_name, >>> content_type = self.content_type, >>> size = file_size, >>> >>> There is a regression test for this BUT --> in the test suite there >>> is # A small file (under the 5M quota) >>> which is governed by >>> (django/tests/regressiontests/file_uploads/uploadhandler.py) >>> >>> def receive_data_chunk(self, raw_data, start): >>> self.total_upload += len(raw_data) >>> if self.total_upload >= self.QUOTA: >>> raise StopUpload(connection_reset=True) >>> return raw_data >>> >>> So obviously my proposed attack is to simply say "content length is >>> tiny" and "this file is actually HUGE". >>> I hope I missed something :) I don't really want this to occur ... >> >> A decent web server such as Apache (under mod_wsgi) will stop reading >> the original content at the content length specified in the request. >> Thus not possible to force more than content length down to the >> application level. >> >> Graham > > The documentation and code in django suggests that this is not the > case. So lets assume we are not using apache but another httpd of some > sort - then this problem will be present. > http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.4 seems to > say otherwise from my reading.
Just to clarify this - I meant that the http content length header item is *not* required - as per http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.4 (also see 4.4.2), so I do not believe that apache would do what you said :) - there is a default limit in a apache of around 2gb for the attackers file to reach though. -- You received this message because you are subscribed to the Google Groups "Django users" group. To post to this group, send email to django-us...@googlegroups.com. To unsubscribe from this group, send email to django-users+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/django-users?hl=en.