Skip to content

Commit

Permalink
Adding FORM_PART_LIMIT for overriding MultipartParser.part_limit (#1251)
Browse files Browse the repository at this point in the history
* Adding FORM_PART_LIMIT for overwriting MultipartParser.part_limit
* Add configuration switch for the max. allowed number of form fields (default 1024)
---------
Co-authored-by: dataflake
  • Loading branch information
drfho authored Feb 18, 2025
1 parent 37dcf30 commit 8744127
Show file tree
Hide file tree
Showing 5 changed files with 26 additions and 2 deletions.
4 changes: 4 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ https://github.com/zopefoundation/Zope/blob/4.x/CHANGES.rst
5.12.1 (unreleased)
-------------------

- Add configuration switch for the maximum allowed number of form fields.
``multipart`` version 1.2.1 introduced a default value of 128, Zope now
sets it to 1024.

- Update to newest compatible versions of dependencies.

- Fix Request test data for stricter ``multipart`` parser.
Expand Down
2 changes: 2 additions & 0 deletions src/ZPublisher/HTTPRequest.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@

# DOS attack protection -- limiting the amount of memory for forms
# probably should become configurable
FORM_PART_LIMIT = 2 ** 10 # limit for individual form parts
FORM_MEMORY_LIMIT = 2 ** 20 # memory limit for forms
FORM_DISK_LIMIT = 2 ** 30 # disk limit for forms
FORM_MEMFILE_LIMIT = 2 ** 12 # limit for `BytesIO` -> temporary file switch
Expand Down Expand Up @@ -1483,6 +1484,7 @@ def __init__(self, fp, environ):
if content_type == "multipart/form-data":
parts = MultipartParser(
fp, options["boundary"],
part_limit=FORM_PART_LIMIT,
mem_limit=FORM_MEMORY_LIMIT,
disk_limit=FORM_DISK_LIMIT,
memfile_limit=FORM_MEMFILE_LIMIT,
Expand Down
8 changes: 6 additions & 2 deletions src/Zope2/Startup/tests/test_schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ def test_dos_protection(self):
from ZPublisher import HTTPRequest

params = ["FORM_%s_LIMIT" % name
for name in ("MEMORY", "DISK", "MEMFILE")]
for name in ("MEMORY", "DISK", "MEMFILE", "PART")]
defaults = {name: getattr(HTTPRequest, name) for name in params}

try:
Expand Down Expand Up @@ -225,11 +225,15 @@ def test_dos_protection(self):
form-memory-limit 1KB
form-disk-limit 1KB
form-memfile-limit 1KB
form-part-limit 2048
</dos_protection>
""")
handleWSGIConfig(None, handler)
for name in params:
self.assertEqual(getattr(HTTPRequest, name), 1024)
if name == 'FORM_PART_LIMIT':
self.assertEqual(getattr(HTTPRequest, name), 2048)
else:
self.assertEqual(getattr(HTTPRequest, name), 1024)
finally:
for name in params:
setattr(HTTPRequest, name, defaults[name])
7 changes: 7 additions & 0 deletions src/Zope2/Startup/wsgischema.xml
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,13 @@
switches from memory to disk.
</description>
</key>

<key name="form-part-limit" datatype="integer" default="1024">
<description>
Limits the maximum number of parameters or form fields. Larger
forms are blocked by the underlying field parser.
</description>
</key>
</sectiontype>


Expand Down
7 changes: 7 additions & 0 deletions src/Zope2/utilities/skel/etc/zope.conf.in
Original file line number Diff line number Diff line change
Expand Up @@ -279,4 +279,11 @@ instancehome $INSTANCE
# Example:
# form-memfile-limit 4KB

# Parameter: form-part-limit
# Description:
# The maximum number of form parameters / fields in a request.
# Larger forms are blocked by the underlying field parser.
# Example:
# form-part-limit 1024

</dos_protection>

0 comments on commit 8744127

Please sign in to comment.