summaryrefslogtreecommitdiffstats
path: root/Lib/urlparse.py
diff options
context:
space:
mode:
authormatthewbelisle-wf <matthew.belisle@workiva.com>2018-10-30 21:16:26 (GMT)
committerVictor Stinner <vstinner@redhat.com>2018-10-30 21:16:26 (GMT)
commitbc6f74a520112d25ef40324e3de4e8187ff2835d (patch)
tree6240dc59ea6b1ca83094e0390f77bc8d013ebf6c /Lib/urlparse.py
parent64ffee7ad2655c7de9b3b6548aad0c317877ec49 (diff)
downloadcpython-bc6f74a520112d25ef40324e3de4e8187ff2835d.zip
cpython-bc6f74a520112d25ef40324e3de4e8187ff2835d.tar.gz
cpython-bc6f74a520112d25ef40324e3de4e8187ff2835d.tar.bz2
bpo-34866: Add max_num_fields to cgi.FieldStorage (GH-9660) (GH-9969)
Adding `max_num_fields` to `cgi.FieldStorage` to make DOS attacks harder by limiting the number of `MiniFieldStorage` objects created by `FieldStorage`. (cherry picked from commit 209144831b0a19715bda3bd72b14a3e6192d9cc1)
Diffstat (limited to 'Lib/urlparse.py')
-rw-r--r--Lib/urlparse.py21
1 files changed, 18 insertions, 3 deletions
diff --git a/Lib/urlparse.py b/Lib/urlparse.py
index 4cd3d67..f7c2b03 100644
--- a/Lib/urlparse.py
+++ b/Lib/urlparse.py
@@ -361,7 +361,7 @@ def unquote(s):
append(item)
return ''.join(res)
-def parse_qs(qs, keep_blank_values=0, strict_parsing=0):
+def parse_qs(qs, keep_blank_values=0, strict_parsing=0, max_num_fields=None):
"""Parse a query given as a string argument.
Arguments:
@@ -378,16 +378,20 @@ def parse_qs(qs, keep_blank_values=0, strict_parsing=0):
strict_parsing: flag indicating what to do with parsing errors.
If false (the default), errors are silently ignored.
If true, errors raise a ValueError exception.
+
+ max_num_fields: int. If set, then throws a ValueError if there
+ are more than n fields read by parse_qsl().
"""
dict = {}
- for name, value in parse_qsl(qs, keep_blank_values, strict_parsing):
+ for name, value in parse_qsl(qs, keep_blank_values, strict_parsing,
+ max_num_fields):
if name in dict:
dict[name].append(value)
else:
dict[name] = [value]
return dict
-def parse_qsl(qs, keep_blank_values=0, strict_parsing=0):
+def parse_qsl(qs, keep_blank_values=0, strict_parsing=0, max_num_fields=None):
"""Parse a query given as a string argument.
Arguments:
@@ -404,8 +408,19 @@ def parse_qsl(qs, keep_blank_values=0, strict_parsing=0):
false (the default), errors are silently ignored. If true,
errors raise a ValueError exception.
+ max_num_fields: int. If set, then throws a ValueError if there
+ are more than n fields read by parse_qsl().
+
Returns a list, as G-d intended.
"""
+ # 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(';')
+ 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(';')]
r = []
for name_value in pairs: