Add ParameterLimitValve to enforce request parameter limits for specific URLs#753
Conversation
- Introduced ParameterLimitValve to allow limiting the number of parameters in HTTP requests. - Added configuration options for global parameter limits and specific limits for URL patterns. - Requests exceeding the configured limits are rejected with an HTTP 400 Bad Request error. - Includes unit tests (TestParameterLimitValve) to ensure full test coverage for the valve's functionality. - Added documentation for the ParameterLimitValve, detailing its attributes, usage, and configuration.
|
This approach could be implemented as a Filter. If we were going to do this, I think something that enforces the limit at the point the parameters are parsed - rather than after - is the way to go. It would mean some refactoring of |
|
While I haven't actually looked at the code (for either Allowing a Valve/Filter to recover from this means that that DoS protection is effectively gone, even if the request is ultimately rejected with a 4xx response. The damage has already been done. |
|
I will refactor the implementation as follows:
Please let me know if this sounds like a reasonable solution, or if there’s anything else to consider that I am missing. |
Hash collisions was why the 10k limit was put in place - CVE-2012-0022. That was chosen as the largest round number that was low enough to avoid the hash collision issue. The further reduction to 1k was on the basis that very few apps need the limit that high and there is a memory cost to handling parameters. The aim was to reduce the minimum amount of RAM Tomcat needed to have and still be able to handle default maximum concurrent requests with default maximum parameters each. Like all the Tomcat defaults, it is a trade-off. |
…t the point when parameters are parsed - rather than after. - Introduced a new maxParameterCount field in Request.java class - Removed configuration option for global parameter limit, as it is replaced by the default Connector's limit. - Replaced unit tests with integration tests to ensure better coverage for the valve's functionality. - Fixed documentation
|
I have refactored the valve and the request as discussed here. |
| valve.invoke(mockRequest, null); | ||
| } catch (NumberFormatException e) { | ||
| Assert.assertNull(mockRequest.getAttribute(Globals.KEY_SIZE_ATTR)); | ||
| mockRequest.setHeader(valve.getSslCipherUserKeySizeHeader(), null); |
There was a problem hiding this comment.
Due to the random ordering of the execution of the tests, I had to reset the header at this point because other tests were throwing NumberFormatException.
- Modified `setUrlPatternLimits` to accept `BufferedReader` input, allowing for flexible configuration from files. - Updated `ParameterLimitValve` to handle configuration files: - Supports `parameter_limit.config` in `/WEB-INF/` for contexts and configurable host-level paths. - Properly parses line-by-line configuration, skipping comments and empty lines. - Handles multiple `=` in patterns by splitting at the last `=`. - Enhanced `invoke` method to apply parameter limits based on decoded URIs and URL patterns. - Added integration tests in `TestParameterLimitValve` - Introduced logging for debugging configuration parsing and application.
22584b7 to
eeb2468
Compare
…fic URLs (#753) Introduce ParameterLimitValve to enforce request parameter limits - Added `ParameterLimitValve`, a new valve that allows enforcing limits on the number of parameters in HTTP requests. - Supports defining per-URL pattern parameter limits using regular expressions. - Requests exceeding the configured limits are rejected with an HTTP 400 Bad Request error. - Configuration is possible through `context.xml` and `server.xml`, or via dynamic management. - Includes integration tests (`TestParameterLimitValve`) to validate enforcement behavior across different contexts. - Added documentation detailing the valve’s attributes, configuration options, and usage examples. (cherry picked from commit ff49f19)
Introduce ParameterLimitValve to enforce request parameter limits - Added `ParameterLimitValve`, a new valve that allows enforcing limits on the number of parameters in HTTP requests. - Supports defining per-URL pattern parameter limits using regular expressions. - Requests exceeding the configured limits are rejected with an HTTP 400 Bad Request error. - Configuration is possible through `context.xml` and `server.xml`, or via dynamic management. - Includes integration tests (`TestParameterLimitValve`) to validate enforcement behavior across different contexts. - Added documentation detailing the valve’s attributes, configuration options, and usage examples.
Introduce ParameterLimitValve to enforce request parameter limits - Added `ParameterLimitValve`, a new valve that allows enforcing limits on the number of parameters in HTTP requests. - Supports defining per-URL pattern parameter limits using regular expressions. - Requests exceeding the configured limits are rejected with an HTTP 400 Bad Request error. - Configuration is possible through `context.xml` and `server.xml`, or via dynamic management. - Includes integration tests (`TestParameterLimitValve`) to validate enforcement behavior across different contexts. - Added documentation detailing the valve’s attributes, configuration options, and usage examples.
This is an effort of introducing Parameter Limit Valve to allow limiting the number of parameters in HTTP requests, but explicitly allowing more parameters for specific URLs. (The idea raised by this email)
It's worth to be noted that if the Parameter Limit Valve is configured, it operates independently of the Connector's maxParameterCount attribute. The Connector's maxParameterCount sets a global limit, while the Parameter Limit Valve offers additional flexibility by allowing different limits for specific URLs. However, if the maxParameterCount defined in the Connector is lower, it effectively overrides the valve by preventing large requests from ever reaching it.
For manual testing one can add something like the following in context.xml
and run some relevant test cases:
curl -X POST http://localhost:8080/api/resource -d "param1=val1¶m2=val2" PASS
curl -X POST http://localhost:8080/api/resource -d "param1=val1¶m2=val2¶m3=val3" FAIL
curl -X POST http://localhost:8080/admin/settings -d "param1=val1" PASS
curl -X POST http://localhost:8080/admin/settings -d "param1=val1¶m2=val2" FAIL
curl -X POST http://localhost:8080/my/special/url1 -d "param1=val1¶m2=val2¶m3=val3" PASS
curl -X POST http://localhost:8080/my/special/url1 -d "param1=val1¶m2=val2¶m3=val3¶m4=val4" FAIL
curl -X POST http://localhost:8080/random -d "param1=val1¶m2=val2¶m3=val3¶m4=val4" PASS
curl -X POST http://localhost:8080/random -d "param1=val1¶m2=val2¶m3=val3¶m4=val4¶m5=val5" FAIL