-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fail-safe on unsupported request framing
If we promise wsgi.input_terminated, we better get it right - or not at all. * chunked encoding on HTTP <= 1.1 * chunked not last transfer coding * multiple chinked codings * any unknown codings (yes, this too! because we do not detect unusual syntax that is still chunked) * empty coding (plausibly harmless, but not see in real life anyway - refused, for the moment)
- Loading branch information
Showing
40 changed files
with
281 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,6 +12,7 @@ | |
InvalidHeader, InvalidHeaderName, NoMoreData, | ||
InvalidRequestLine, InvalidRequestMethod, InvalidHTTPVersion, | ||
LimitRequestLine, LimitRequestHeaders, | ||
UnsupportedTransferCoding, | ||
) | ||
from gunicorn.http.errors import InvalidProxyLine, ForbiddenProxyRequest | ||
from gunicorn.http.errors import InvalidSchemeHeaders | ||
|
@@ -39,6 +40,7 @@ def __init__(self, cfg, unreader, peer_addr): | |
self.trailers = [] | ||
self.body = None | ||
self.scheme = "https" if cfg.is_ssl else "http" | ||
self.must_close = False | ||
|
||
# set headers limits | ||
self.limit_request_fields = cfg.limit_request_fields | ||
|
@@ -58,6 +60,9 @@ def __init__(self, cfg, unreader, peer_addr): | |
self.unreader.unread(unused) | ||
self.set_body_reader() | ||
|
||
def force_close(self): | ||
self.must_close = True | ||
|
||
def parse(self, unreader): | ||
raise NotImplementedError() | ||
|
||
|
@@ -152,9 +157,47 @@ def set_body_reader(self): | |
content_length = value | ||
elif name == "TRANSFER-ENCODING": | ||
if value.lower() == "chunked": | ||
# DANGER: transer codings stack, and stacked chunking is never intended | ||
if chunked: | ||
raise InvalidHeader("TRANSFER-ENCODING", req=self) | ||
chunked = True | ||
elif value.lower() == "identity": | ||
# does not do much, could still plausibly desync from what the proxy does | ||
# safe option: nuke it, its never needed | ||
if chunked: | ||
raise InvalidHeader("TRANSFER-ENCODING", req=self) | ||
elif value.lower() == "": | ||
# lacking security review on this case | ||
# offer the option to restore previous behaviour, but refuse by default, for now | ||
self.force_close() | ||
if not self.cfg.tolerate_dangerous_framing: | ||
raise UnsupportedTransferCoding(value) | ||
# DANGER: do not change lightly; ref: request smuggling | ||
This comment has been minimized.
Sorry, something went wrong.
This comment has been minimized.
Sorry, something went wrong.
marcaurele
|
||
# T-E is a list and we *could* support correctly parsing its elements | ||
# .. but that is only safe after getting all the edge cases right | ||
# .. for which no real-world need exists, so best to NOT open that can of worms | ||
else: | ||
self.force_close() | ||
# even if parser is extended, retain this branch: | ||
# the "chunked not last" case remains to be rejected! | ||
raise UnsupportedTransferCoding(value) | ||
|
||
if chunked: | ||
# two potentially dangerous cases: | ||
# a) CL + TE (TE overrides CL.. only safe if the recipient sees it that way too) | ||
# b) chunked HTTP/1.0 (always faulty) | ||
if self.version < (1, 1): | ||
# framing wonky, see RFC 9112 Section 6.1 | ||
self.force_close() | ||
if not self.cfg.tolerate_dangerous_framing: | ||
raise InvalidHeader("TRANSFER-ENCODING", req=self) | ||
if content_length is not None: | ||
# we cannot be certain the message framing we understood matches proxy intent | ||
# -> whatever happens next, remaining input must not be trusted | ||
self.force_close() | ||
# either processing or rejecting is permitted in RFC 9112 Section 6.1 | ||
if not self.cfg.tolerate_dangerous_framing: | ||
raise InvalidHeader("CONTENT-LENGTH", req=self) | ||
self.body = Body(ChunkedReader(self, self.unreader)) | ||
elif content_length is not None: | ||
try: | ||
|
@@ -173,6 +216,8 @@ def set_body_reader(self): | |
self.body = Body(EOFReader(self.unreader)) | ||
|
||
def should_close(self): | ||
if self.must_close: | ||
return True | ||
for (h, v) in self.headers: | ||
if h == "CONNECTION": | ||
v = v.lower().strip(" \t") | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
POST /chunked_w_underscore_chunk_size HTTP/1.1\r\n | ||
Transfer-Encoding: chunked\r\n | ||
\r\n | ||
5\r\n | ||
hello\r\n | ||
6_0\r\n | ||
world\r\n | ||
0\r\n | ||
\r\n | ||
POST /after HTTP/1.1\r\n | ||
Transfer-Encoding: identity\r\n | ||
\r\n |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
from gunicorn.http.errors import InvalidChunkSize | ||
request = InvalidChunkSize |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
POST /chunked_with_prefixed_value HTTP/1.1\r\n | ||
Content-Length: 12\r\n | ||
Transfer-Encoding: \tchunked\r\n | ||
\r\n | ||
5\r\n | ||
hello\r\n | ||
6\r\n | ||
world\r\n | ||
\r\n |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
from gunicorn.http.errors import InvalidHeader | ||
request = InvalidHeader |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
POST /double_chunked HTTP/1.1\r\n | ||
Transfer-Encoding: identity, chunked, identity, chunked\r\n | ||
\r\n | ||
5\r\n | ||
hello\r\n | ||
6\r\n | ||
world\r\n | ||
\r\n |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
from gunicorn.http.errors import UnsupportedTransferCoding | ||
request = UnsupportedTransferCoding |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
POST /chunked_twice HTTP/1.1\r\n | ||
Transfer-Encoding: identity\r\n | ||
Transfer-Encoding: chunked\r\n | ||
Transfer-Encoding: identity\r\n | ||
Transfer-Encoding: chunked\r\n | ||
\r\n | ||
5\r\n | ||
hello\r\n | ||
6\r\n | ||
world\r\n | ||
\r\n |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
from gunicorn.http.errors import InvalidHeader | ||
request = InvalidHeader |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
POST /chunked_HTTP_1.0 HTTP/1.0\r\n | ||
Transfer-Encoding: chunked\r\n | ||
\r\n | ||
5\r\n | ||
hello\r\n | ||
6\r\n | ||
world\r\n | ||
0\r\n | ||
Vary: *\r\n | ||
Content-Type: text/plain\r\n | ||
\r\n |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
from gunicorn.http.errors import InvalidHeader | ||
request = InvalidHeader |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
POST /chunked_not_last HTTP/1.1\r\n | ||
Transfer-Encoding: chunked\r\n | ||
Transfer-Encoding: gzip\r\n | ||
\r\n | ||
5\r\n | ||
hello\r\n | ||
6\r\n | ||
world\r\n | ||
\r\n |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
from gunicorn.http.errors import UnsupportedTransferCoding | ||
request = UnsupportedTransferCoding |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
POST /chunked_not_last HTTP/1.1\r\n | ||
Transfer-Encoding: chunked\r\n | ||
Transfer-Encoding: identity\r\n | ||
\r\n | ||
5\r\n | ||
hello\r\n | ||
6\r\n | ||
world\r\n | ||
\r\n |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
from gunicorn.http.errors import InvalidHeader | ||
request = InvalidHeader |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
GETß /germans.. HTTP/1.1\r\n | ||
Content-Length: 3\r\n | ||
\r\n | ||
ÄÄÄ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
from gunicorn.config import Config | ||
from gunicorn.http.errors import InvalidRequestMethod | ||
|
||
cfg = Config() | ||
request = InvalidRequestMethod |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
GETÿ /french.. HTTP/1.1\r\n | ||
Content-Length: 3\r\n | ||
\r\n | ||
ÄÄÄ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
from gunicorn.config import Config | ||
from gunicorn.http.errors import InvalidRequestMethod | ||
|
||
cfg = Config() | ||
request = InvalidRequestMethod |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
GET /french.. HTTP/1.1\r\n | ||
Content-Lengthÿ: 3\r\n | ||
Content-Length: 3\r\n | ||
\r\n | ||
ÄÄÄ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
from gunicorn.config import Config | ||
from gunicorn.http.errors import InvalidHeaderName | ||
|
||
cfg = Config() | ||
request = InvalidHeaderName |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
GET\0PROXY /foo HTTP/1.1\r\n | ||
\r\n |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
from gunicorn.http.errors import InvalidRequestMethod | ||
request = InvalidRequestMethod |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
GET\0 /foo HTTP/1.1\r\n | ||
\r\n |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
from gunicorn.http.errors import InvalidRequestMethod | ||
request = InvalidRequestMethod |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
GET /stuff/here?foo=bar HTTP/1.1\r\n | ||
Content-Length: 0 1\r\n | ||
\r\n | ||
x |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
from gunicorn.config import Config | ||
from gunicorn.http.errors import InvalidHeader | ||
|
||
cfg = Config() | ||
request = InvalidHeader |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
GET /stuff/here?foo=bar HTTP/1.1\r\n | ||
Content-Length: 3 1\r\n | ||
\r\n | ||
xyz | ||
abc123 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
from gunicorn.config import Config | ||
from gunicorn.http.errors import InvalidHeader | ||
|
||
cfg = Config() | ||
request = InvalidHeader |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
GET: /stuff/here?foo=bar HTTP/1.1\r\n | ||
Content-Length: 3\r\n | ||
\r\n | ||
xyz |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
from gunicorn.config import Config | ||
from gunicorn.http.errors import InvalidRequestMethod | ||
|
||
cfg = Config() | ||
request = InvalidRequestMethod |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
POST /chunked_cont_h_at_first HTTP/1.1\r\n | ||
Transfer-Encoding: chunked\r\n | ||
\r\n | ||
5; some; parameters=stuff\r\n | ||
hello\r\n | ||
6; blahblah; blah\r\n | ||
world\r\n | ||
0\r\n | ||
\r\n | ||
PUT /chunked_cont_h_at_last HTTP/1.1\r\n | ||
Transfer-Encoding: chunked\r\n | ||
Content-Length: -1\r\n | ||
\r\n | ||
5; some; parameters=stuff\r\n | ||
hello\r\n | ||
6; blahblah; blah\r\n | ||
world\r\n | ||
0\r\n |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
from gunicorn.config import Config | ||
|
||
cfg = Config() | ||
cfg.set("tolerate_dangerous_framing", True) | ||
|
||
req1 = { | ||
"method": "POST", | ||
"uri": uri("/chunked_cont_h_at_first"), | ||
"version": (1, 1), | ||
"headers": [ | ||
("TRANSFER-ENCODING", "chunked") | ||
], | ||
"body": b"hello world" | ||
} | ||
|
||
req2 = { | ||
"method": "PUT", | ||
"uri": uri("/chunked_cont_h_at_last"), | ||
"version": (1, 1), | ||
"headers": [ | ||
("TRANSFER-ENCODING", "chunked"), | ||
("CONTENT-LENGTH", "-1"), | ||
], | ||
"body": b"hello world" | ||
} | ||
|
||
request = [req1, req2] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
@pajod does this fix https://nvd.nist.gov/vuln/detail/CVE-2024-1135?