Skip to content

Commit

Permalink
Backport bpo-44022: Fix http client infinite line reading (DoS) after…
Browse files Browse the repository at this point in the history
… a HTTP 100 Continue (pythonGH-25916)

Backport the fix from the following commit:

    commit 47895e3
    Author: Gen Xu <xgbarry@gmail.com>
    Date:   2021-05-06 00:42:41 +0200

        bpo-44022: Fix http client infinite line reading (DoS) after a HTTP 100 Continue (pythonGH-25916)

        Fixes http.client potential denial of service where it could get stuck reading lines from a malicious server after a 100 Continue response.

        Co-authored-by: Gregory P. Smith <greg@krypto.org>

Instead of reusing the header reading code, I have just added explicit
counter to avoid having to refactor the old code.

Plus the improved test from:

    commit e60ab84
    Author: Gregory P. Smith <greg@krypto.org>
    Date:   2021-06-03 05:43:38 +0200

        bpo-44022: Improve the regression test. (pythonGH-26503)

        It wasn't actually detecting the regression due to the
        assertion being too lenient.
  • Loading branch information
mgorny committed Jun 19, 2021
1 parent 41823e6 commit dae96ac
Show file tree
Hide file tree
Showing 2 changed files with 17 additions and 1 deletion.
5 changes: 4 additions & 1 deletion Lib/httplib.py
Original file line number Diff line number Diff line change
Expand Up @@ -453,11 +453,14 @@ def begin(self):
if status != CONTINUE:
break
# skip the header from the 100 response
header_count = 0
while True:
skip = self.fp.readline(_MAXLINE + 1)
if len(skip) > _MAXLINE:
raise LineTooLong("header line")
skip = skip.strip()
header_count += 1
if header_count > _MAXHEADERS:
raise HTTPException("got more than %d headers" % _MAXHEADERS)
if not skip:
break
if self.debuglevel > 0:
Expand Down
13 changes: 13 additions & 0 deletions Lib/test/test_httplib.py
Original file line number Diff line number Diff line change
Expand Up @@ -675,6 +675,19 @@ def test_overflowing_header_line(self):
resp = httplib.HTTPResponse(FakeSocket(body))
self.assertRaises(httplib.LineTooLong, resp.begin)

def test_overflowing_header_limit_after_100(self):
body = (
'HTTP/1.1 100 OK\r\n'
'r\n' * 32768
)
resp = httplib.HTTPResponse(FakeSocket(body))
with self.assertRaises(httplib.HTTPException) as cm:
resp.begin()
# We must assert more because other reasonable errors that we
# do not want can also be HTTPException derived.
self.assertIn('got more than ', str(cm.exception))
self.assertIn('headers', str(cm.exception))

def test_overflowing_chunked_line(self):
body = (
'HTTP/1.1 200 OK\r\n'
Expand Down

0 comments on commit dae96ac

Please sign in to comment.