Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Handle GET, HEAD, and OPTIONS correctly in ContentLengthLimit #989

Merged
merged 6 commits into from May 5, 2022

Conversation

davidpdrsn
Copy link
Member

Motivation

ContentLengthLimit is normally applied to a single handler as a regular extractor. However nothing prevents the user from doing .layer(from_extractor::<ContentLengthLimit<(),1024>>()) to limit the size of payloads to all handlers. This doesn't work though since browsers don't send a content-length header on GET requests causing ContentLengthLimit to reject the request.

Solution

Change ContentLengthLimit to accept GET, HEAD, and OPTIONS requests that don't have a content-length header.

We discussed this a bit in Discord and landed on rejecting GET, HEAD, and OPTIONS requests that have a content-length.

We also agreed on not changing the body to an empty body.

I'd categorize this as a bug fix but I could see some making the argument that its a breaking change. Let me know what you think.

cc @neoeinstein

Comment on lines 9 to 10
/// `GET`, `HEAD`, and `OPTIONS` requests are reject if they have a `Content-Length` header,
/// otherwise they're accepted without the body being checked.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What will hyper do to requests with one of these methods that do have a body? Could this create an additional attack surface in practice?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hyper is fine with GET requests with bodies.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh but it stops reading after content-length bytes are reached, or doesn't read the body at all if there is no content-length?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If there is a content-length it stops reading after the length, if there is no content-length (and no chunked encoding) it doesn't read the body and it appears empty to the user.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The body is assumed to be empty if there is no Transfer-Encoding or Content-Length header. If there is a Content-Length header, hyper will stop reading once Content-Length bytes have been read.

The one hole here that we may want to close: If a GET, HEAD, or OPTIONS doesn't have a Content-Length header, but does have a Transfer-Encoding header, then this extractor should reject the request (same as if missing the Content-Length header). That will prevent a body being smuggled into a GET/HEAD/OPTIONS request where we can't verify the length limit.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll fix that!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@neoeinstein I believe 711cc3e should do it!

Copy link
Contributor

@neoeinstein neoeinstein left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One typo change and a pattern-matching improvement.

axum/src/extract/content_length_limit.rs Outdated Show resolved Hide resolved
axum/src/extract/content_length_limit.rs Outdated Show resolved Hide resolved
Co-authored-by: Marcus Griep <marcus@griep.us>
Co-authored-by: Jonas Platte <jplatte+git@posteo.de>
@davidpdrsn davidpdrsn changed the title Handle GET, HEAD, and OPTIONS correctly ContentLengthLimit Handle GET, HEAD, and OPTIONS correctly in ContentLengthLimit May 3, 2022
@davidpdrsn davidpdrsn merged commit d19beff into main May 5, 2022
@davidpdrsn davidpdrsn deleted the handle-get-in-content-length-rejection branch May 5, 2022 07:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants