Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

max_content_length is not enforced in all cases #690

Closed
danc86 opened this issue Feb 13, 2015 · 6 comments · Fixed by #2620
Closed

max_content_length is not enforced in all cases #690

danc86 opened this issue Feb 13, 2015 · 6 comments · Fixed by #2620
Labels
Milestone

Comments

@danc86
Copy link

danc86 commented Feb 13, 2015

The wording in the docs about the max_content_length property indicates that it applies for all usages of the request, including when accessing the raw request data.

Special note on the get_data method: Calling this loads the full request data into memory. This is only safe to do if the max_content_length is set.
[...]
To avoid being the victim of a DDOS attack you can set the maximum accepted content length and request field sizes. The BaseRequest class has two attributes for that: max_content_length and max_form_memory_size.
The first one can be used to limit the total content length. For example by setting it to 1024 * 1024 * 16 the request won’t accept more than 16MB of transmitted data.
[...]

However in Werkzeug 0.9+ it actually only applies when form data is parsed (and that's the only case covered by tests). The length is not enforced when .get_data() is called.

Failing test case:

def test_content_length_limiting():
    data = b'Hello World'
    req = wrappers.Request.from_values(input_stream=BytesIO(data),
            content_length=len(data), method='POST')
    req.max_content_length = 400
    strict_eq(req.get_data(), data)

    req = wrappers.Request.from_values(input_stream=BytesIO(data),
            content_length=len(data), method='POST')
    req.max_content_length = 4
    pytest.raises(RequestEntityTooLarge, lambda: req.get_data())
@danc86
Copy link
Author

danc86 commented Feb 13, 2015

Note that this is a regression in 0.9. In 0.8 the .data property unconditionally attempted form parsing, which triggered the length checks, but in 0.9 the form parsing is skipped if the content type is not suitable.

@danc86
Copy link
Author

danc86 commented Feb 13, 2015

Also, I guess it's a security issue since any application which is using .get_data() and is relying on .max_content_length to enforce length restrictions is now subject to memory exhaustion DoS with Werkzeug 0.9...

@untitaker
Copy link
Contributor

I suppose this really is a security and design issue. Since form parsing is now optional, length checks have to occur outside of FormDataParser.

@untitaker
Copy link
Contributor

@mitsuhiko said in IRC that this value was never really enforced.

We also talked about the fact that Werkzeug's request object isn't actually the right place for such functionality. For this reason, I'd rather move this functionality into a middleware, but this is going to take some time and isn't appropriate for a bugfix release.

@davidism
Copy link
Member

davidism commented Jan 20, 2019

Production WSGI servers handle terminating input, and can indicate it in cases where content length isn't set by setting wsgi.input_terminated in the environ. HTTP servers like Nginx and some WSGI servers like uWSGI can set limits on the request body. Request.max_content_length isn't particularly useful now, it's better handled at another layer.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Nov 13, 2020
@davidism
Copy link
Member

Fixed by #2620

@davidism davidism added this to the 2.3.0 milestone Mar 14, 2023
# for free to subscribe to this conversation on GitHub. Already have an account? #.
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants