diff options
| author | Nick Pope <nick@nickpope.me.uk> | 2021-02-16 10:14:17 +0000 |
|---|---|---|
| committer | Carlton Gibson <carlton.gibson@noumenal.es> | 2021-02-19 09:15:09 +0100 |
| commit | be8237c7cce24b06aabde0b97afce98ddabbe3b6 (patch) | |
| tree | b4a01e3e621eaf21fe64dc33c081b94c37ca1600 /django | |
| parent | 0debc6ba5b99027dccd287f8c247b328e4fe9483 (diff) | |
[3.2.x] Fixed CVE-2021-23336 -- Fixed web cache poisoning via django.utils.http.parse_qsl().
Diffstat (limited to 'django')
| -rw-r--r-- | django/http/request.py | 5 | ||||
| -rw-r--r-- | django/utils/http.py | 16 |
2 files changed, 15 insertions, 6 deletions
diff --git a/django/http/request.py b/django/http/request.py index 2488bf9ccd..195341ec4b 100644 --- a/django/http/request.py +++ b/django/http/request.py @@ -29,7 +29,10 @@ from .multipartparser import parse_header # detect whether the max_num_fields argument is available as this security fix # was backported to Python 3.6.8 and 3.7.2, and may also have been applied by # downstream package maintainers to other versions in their repositories. -if not func_supports_parameter(parse_qsl, 'max_num_fields'): +if ( + not func_supports_parameter(parse_qsl, 'max_num_fields') or + not func_supports_parameter(parse_qsl, 'separator') +): from django.utils.http import parse_qsl diff --git a/django/utils/http.py b/django/utils/http.py index 810d7970ba..61db5e6028 100644 --- a/django/utils/http.py +++ b/django/utils/http.py @@ -415,13 +415,13 @@ def _url_has_allowed_host_and_scheme(url, allowed_hosts, require_https=False): # TODO: Remove when dropping support for PY37. def parse_qsl( qs, keep_blank_values=False, strict_parsing=False, encoding='utf-8', - errors='replace', max_num_fields=None, + errors='replace', max_num_fields=None, separator='&', ): """ Return a list of key/value tuples parsed from query string. - Backport of urllib.parse.parse_qsl() from Python 3.8. - Copyright (C) 2020 Python Software Foundation (see LICENSE.python). + Backport of urllib.parse.parse_qsl() from Python 3.8.8. + Copyright (C) 2021 Python Software Foundation (see LICENSE.python). ---- @@ -447,19 +447,25 @@ def parse_qsl( max_num_fields: int. If set, then throws a ValueError if there are more than n fields read by parse_qsl(). + separator: str. The symbol to use for separating the query arguments. + Defaults to &. + Returns a list, as G-d intended. """ qs, _coerce_result = _coerce_args(qs) + if not separator or not isinstance(separator, (str, bytes)): + raise ValueError('Separator must be of type string or bytes.') + # If max_num_fields is defined then check that the number of fields is less # than max_num_fields. This prevents a memory exhaustion DOS attack via # post bodies with many fields. if max_num_fields is not None: - num_fields = 1 + qs.count('&') + qs.count(';') + num_fields = 1 + qs.count(separator) if max_num_fields < num_fields: raise ValueError('Max number of fields exceeded') - pairs = [s2 for s1 in qs.split('&') for s2 in s1.split(';')] + pairs = [s1 for s1 in qs.split(separator)] r = [] for name_value in pairs: if not name_value and not strict_parsing: |
