From 190d441e1e7b6d502dcae383f66e792e4283ea9c Mon Sep 17 00:00:00 2001 From: Lachlan Roberts Date: Wed, 4 Sep 2024 16:45:53 +1000 Subject: [PATCH] Add documentation for form limits & improve configuration via context attributes Signed-off-by: Lachlan Roberts --- .../programming/security/FormSizeDocs.java | 17 ++++++ .../jetty/modules/programming-guide/nav.adoc | 1 + .../pages/security/configuring-form-size.adoc | 56 +++++++++++++++++++ .../ee10/servlet/ServletContextHandler.java | 40 +++++++++++++ .../jetty/ee10/webapp/WebAppContext.java | 3 + .../ee11/servlet/ServletContextHandler.java | 40 +++++++++++++ .../jetty/ee11/webapp/WebAppContext.java | 3 + .../jetty/ee9/nested/ContextHandler.java | 44 ++++++++++++++- .../jetty/ee9/webapp/WebAppContext.java | 2 + 9 files changed, 205 insertions(+), 1 deletion(-) create mode 100644 documentation/jetty/modules/code/examples/src/main/java/org/eclipse/jetty/docs/programming/security/FormSizeDocs.java create mode 100644 documentation/jetty/modules/programming-guide/pages/security/configuring-form-size.adoc diff --git a/documentation/jetty/modules/code/examples/src/main/java/org/eclipse/jetty/docs/programming/security/FormSizeDocs.java b/documentation/jetty/modules/code/examples/src/main/java/org/eclipse/jetty/docs/programming/security/FormSizeDocs.java new file mode 100644 index 00000000000..9717c338d14 --- /dev/null +++ b/documentation/jetty/modules/code/examples/src/main/java/org/eclipse/jetty/docs/programming/security/FormSizeDocs.java @@ -0,0 +1,17 @@ +package org.eclipse.jetty.docs.programming.security; + +import org.eclipse.jetty.ee10.servlet.ServletContextHandler; + +public class FormSizeDocs +{ + public void example() + { + ServletContextHandler servletContextHandler = new ServletContextHandler(); + int maxSizeInBytes = 1024; + int formKeys = 100; + // tag::formSizeConfig[] + servletContextHandler.setMaxFormContentSize(maxSizeInBytes); + servletContextHandler.setMaxFormKeys(formKeys); + // end::formSizeConfig[] + } +} diff --git a/documentation/jetty/modules/programming-guide/nav.adoc b/documentation/jetty/modules/programming-guide/nav.adoc index d4571b36f3e..92465954139 100644 --- a/documentation/jetty/modules/programming-guide/nav.adoc +++ b/documentation/jetty/modules/programming-guide/nav.adoc @@ -44,6 +44,7 @@ ** xref:troubleshooting/component-dump.adoc[] ** xref:troubleshooting/debugging.adoc[] * Jetty Security +** xref:security/configuring-form-size.adoc[] ** xref:security/siwe-support.adoc[] * Migration Guides ** xref:migration/94-to-10.adoc[] diff --git a/documentation/jetty/modules/programming-guide/pages/security/configuring-form-size.adoc b/documentation/jetty/modules/programming-guide/pages/security/configuring-form-size.adoc new file mode 100644 index 00000000000..25f206dc473 --- /dev/null +++ b/documentation/jetty/modules/programming-guide/pages/security/configuring-form-size.adoc @@ -0,0 +1,56 @@ +// +// ======================================================================== +// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others. +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License v. 2.0 which is available at +// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// ======================================================================== +// + +[[configuring-form-size]] += Limiting Form Content + +Form content sent to the server is processed by Jetty into a map of parameters to be used by the web application. +This can be vulnerable to denial of service (DOS) attacks since significant memory and CPU can be consumed if a malicious clients sends very large form content or large number of form keys. +Thus, Jetty limits the amount of data and keys that can be in a form posted to Jetty. + +The default maximum size Jetty permits is 200000 bytes and 1000 keys. +You can change this default for a particular webapp or for all webapps on a particular Server instance. + +== Configuring Form Limits for a Webapp + +To configure the form limits for a single web application, the servlet context handler (or webappContext) instance must be configured using the following methods: + +[,java,indent=0] +---- +include::code:example$src/main/java/org/eclipse/jetty/docs/programming/security/FormSizeDocs.java[tags=formSizeConfig] +---- + +These methods may be called directly when embedding Jetty, but more commonly are configured from a context XML file or WEB-INF/jetty-web.xml file: + +[,xml,subs=attributes+] +---- + + + ... + + 200000 + 200 + + +---- + +These settings can also be set via the following Context attributes. + +- `org.eclipse.jetty.server.Request.maxFormKeys` +- `org.eclipse.jetty.server.Request.maxFormContentSize` + +== Configuring Default Form Limits for the Server + +The default `maxFormKeys` is 1000 and the default `maxFormContentSize` is 200000. + +However, the following system properties can be set to change the default values of this across every context; `org.eclipse.jetty.server.Request.maxFormKeys` and `org.eclipse.jetty.server.Request.maxFormContentSize`. diff --git a/jetty-ee10/jetty-ee10-servlet/src/main/java/org/eclipse/jetty/ee10/servlet/ServletContextHandler.java b/jetty-ee10/jetty-ee10-servlet/src/main/java/org/eclipse/jetty/ee10/servlet/ServletContextHandler.java index ce6aedc8cf4..c94bb0d9813 100644 --- a/jetty-ee10/jetty-ee10-servlet/src/main/java/org/eclipse/jetty/ee10/servlet/ServletContextHandler.java +++ b/jetty-ee10/jetty-ee10-servlet/src/main/java/org/eclipse/jetty/ee10/servlet/ServletContextHandler.java @@ -318,6 +318,8 @@ public class ServletContextHandler extends ContextHandler public void dump(Appendable out, String indent) throws IOException { dumpObjects(out, indent, + Dumpable.named("maxFormKeys ", getMaxFormKeys()), + Dumpable.named("maxFormContentSize ", getMaxFormContentSize()), new ClassLoaderDump(getClassLoader()), Dumpable.named("context " + this, getContext()), Dumpable.named("handler attributes " + this, getContext().getPersistentAttributes()), @@ -2043,6 +2045,44 @@ public class ServletContextHandler extends ContextHandler { _servletContext.setExtendedListenerTypes(b); } + + @Override + public Object getAttribute(String name) + { + return switch (name) + { + case FormFields.MAX_FIELDS_ATTRIBUTE -> getMaxFormKeys(); + case FormFields.MAX_LENGTH_ATTRIBUTE -> getMaxFormContentSize(); + default -> super.getAttribute(name); + }; + } + + @Override + public Object setAttribute(String name, Object attribute) + { + return switch (name) + { + case FormFields.MAX_FIELDS_ATTRIBUTE -> + { + int oldValue = getMaxFormKeys(); + if (attribute == null) + setMaxFormKeys(DEFAULT_MAX_FORM_KEYS); + else + setMaxFormKeys(Integer.parseInt(attribute.toString())); + yield oldValue; + } + case FormFields.MAX_LENGTH_ATTRIBUTE -> + { + int oldValue = getMaxFormContentSize(); + if (attribute == null) + setMaxFormContentSize(DEFAULT_MAX_FORM_CONTENT_SIZE); + else + setMaxFormContentSize(Integer.parseInt(attribute.toString())); + yield oldValue; + } + default -> super.setAttribute(name, attribute); + }; + } } public class ServletContextApi implements jakarta.servlet.ServletContext diff --git a/jetty-ee10/jetty-ee10-webapp/src/main/java/org/eclipse/jetty/ee10/webapp/WebAppContext.java b/jetty-ee10/jetty-ee10-webapp/src/main/java/org/eclipse/jetty/ee10/webapp/WebAppContext.java index 1fd30b5e234..1fc2a0adbaf 100644 --- a/jetty-ee10/jetty-ee10-webapp/src/main/java/org/eclipse/jetty/ee10/webapp/WebAppContext.java +++ b/jetty-ee10/jetty-ee10-webapp/src/main/java/org/eclipse/jetty/ee10/webapp/WebAppContext.java @@ -60,6 +60,7 @@ import org.eclipse.jetty.util.URIUtil; import org.eclipse.jetty.util.annotation.ManagedAttribute; import org.eclipse.jetty.util.annotation.ManagedObject; import org.eclipse.jetty.util.component.ClassLoaderDump; +import org.eclipse.jetty.util.component.Dumpable; import org.eclipse.jetty.util.component.DumpableCollection; import org.eclipse.jetty.util.resource.Resource; import org.eclipse.jetty.util.resource.ResourceFactory; @@ -986,6 +987,8 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL name = String.format("%s@%x", name, hashCode()); dumpObjects(out, indent, + Dumpable.named("maxFormKeys ", getMaxFormKeys()), + Dumpable.named("maxFormContentSize ", getMaxFormContentSize()), new ClassLoaderDump(getClassLoader()), new DumpableCollection("Systemclasses " + name, systemClasses), new DumpableCollection("Serverclasses " + name, serverClasses), diff --git a/jetty-ee11/jetty-ee11-servlet/src/main/java/org/eclipse/jetty/ee11/servlet/ServletContextHandler.java b/jetty-ee11/jetty-ee11-servlet/src/main/java/org/eclipse/jetty/ee11/servlet/ServletContextHandler.java index 2598c650112..ff4316d59e4 100644 --- a/jetty-ee11/jetty-ee11-servlet/src/main/java/org/eclipse/jetty/ee11/servlet/ServletContextHandler.java +++ b/jetty-ee11/jetty-ee11-servlet/src/main/java/org/eclipse/jetty/ee11/servlet/ServletContextHandler.java @@ -316,6 +316,8 @@ public class ServletContextHandler extends ContextHandler public void dump(Appendable out, String indent) throws IOException { dumpObjects(out, indent, + Dumpable.named("maxFormKeys ", getMaxFormKeys()), + Dumpable.named("maxFormContentSize ", getMaxFormContentSize()), new ClassLoaderDump(getClassLoader()), Dumpable.named("context " + this, getContext()), Dumpable.named("handler attributes " + this, getContext().getPersistentAttributes()), @@ -2037,6 +2039,44 @@ public class ServletContextHandler extends ContextHandler { _servletContext.setExtendedListenerTypes(b); } + + @Override + public Object getAttribute(String name) + { + return switch (name) + { + case FormFields.MAX_FIELDS_ATTRIBUTE -> getMaxFormKeys(); + case FormFields.MAX_LENGTH_ATTRIBUTE -> getMaxFormContentSize(); + default -> super.getAttribute(name); + }; + } + + @Override + public Object setAttribute(String name, Object attribute) + { + return switch (name) + { + case FormFields.MAX_FIELDS_ATTRIBUTE -> + { + int oldValue = getMaxFormKeys(); + if (attribute == null) + setMaxFormKeys(DEFAULT_MAX_FORM_KEYS); + else + setMaxFormKeys(Integer.parseInt(attribute.toString())); + yield oldValue; + } + case FormFields.MAX_LENGTH_ATTRIBUTE -> + { + int oldValue = getMaxFormContentSize(); + if (attribute == null) + setMaxFormContentSize(DEFAULT_MAX_FORM_CONTENT_SIZE); + else + setMaxFormContentSize(Integer.parseInt(attribute.toString())); + yield oldValue; + } + default -> super.setAttribute(name, attribute); + }; + } } public class ServletContextApi implements jakarta.servlet.ServletContext diff --git a/jetty-ee11/jetty-ee11-webapp/src/main/java/org/eclipse/jetty/ee11/webapp/WebAppContext.java b/jetty-ee11/jetty-ee11-webapp/src/main/java/org/eclipse/jetty/ee11/webapp/WebAppContext.java index a4046ac43a4..298f8e7fe99 100644 --- a/jetty-ee11/jetty-ee11-webapp/src/main/java/org/eclipse/jetty/ee11/webapp/WebAppContext.java +++ b/jetty-ee11/jetty-ee11-webapp/src/main/java/org/eclipse/jetty/ee11/webapp/WebAppContext.java @@ -60,6 +60,7 @@ import org.eclipse.jetty.util.URIUtil; import org.eclipse.jetty.util.annotation.ManagedAttribute; import org.eclipse.jetty.util.annotation.ManagedObject; import org.eclipse.jetty.util.component.ClassLoaderDump; +import org.eclipse.jetty.util.component.Dumpable; import org.eclipse.jetty.util.component.DumpableCollection; import org.eclipse.jetty.util.resource.Resource; import org.eclipse.jetty.util.resource.ResourceFactory; @@ -882,6 +883,8 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL name = String.format("%s@%x", name, hashCode()); dumpObjects(out, indent, + Dumpable.named("maxFormKeys ", getMaxFormKeys()), + Dumpable.named("maxFormContentSize ", getMaxFormContentSize()), new ClassLoaderDump(getClassLoader()), new DumpableCollection("Protected classes " + name, protectedClasses), new DumpableCollection("Hidden classes " + name, hiddenClasses), diff --git a/jetty-ee9/jetty-ee9-nested/src/main/java/org/eclipse/jetty/ee9/nested/ContextHandler.java b/jetty-ee9/jetty-ee9-nested/src/main/java/org/eclipse/jetty/ee9/nested/ContextHandler.java index dfe73d44112..318b1f99bce 100644 --- a/jetty-ee9/jetty-ee9-nested/src/main/java/org/eclipse/jetty/ee9/nested/ContextHandler.java +++ b/jetty-ee9/jetty-ee9-nested/src/main/java/org/eclipse/jetty/ee9/nested/ContextHandler.java @@ -92,6 +92,7 @@ import org.eclipse.jetty.util.TypeUtil; import org.eclipse.jetty.util.URIUtil; import org.eclipse.jetty.util.annotation.ManagedAttribute; import org.eclipse.jetty.util.annotation.ManagedObject; +import org.eclipse.jetty.util.component.Dumpable; import org.eclipse.jetty.util.component.DumpableCollection; import org.eclipse.jetty.util.component.Environment; import org.eclipse.jetty.util.component.LifeCycle; @@ -300,7 +301,10 @@ public class ContextHandler extends ScopedHandler implements Attributes, Supplie @Override public void dump(Appendable out, String indent) throws IOException { - dumpObjects(out, indent, new DumpableCollection("initparams " + this, getInitParams().entrySet())); + dumpObjects(out, indent, + Dumpable.named("maxFormKeys ", getMaxFormKeys()), + Dumpable.named("maxFormContentSize ", getMaxFormContentSize()), + new DumpableCollection("initparams " + this, getInitParams().entrySet())); } public APIContext getServletContext() @@ -2858,6 +2862,44 @@ public class ContextHandler extends ScopedHandler implements Attributes, Supplie { return _apiContext; } + + @Override + public Object getAttribute(String name) + { + return switch (name) + { + case FormFields.MAX_FIELDS_ATTRIBUTE -> getMaxFormKeys(); + case FormFields.MAX_LENGTH_ATTRIBUTE -> getMaxFormContentSize(); + default -> super.getAttribute(name); + }; + } + + @Override + public Object setAttribute(String name, Object attribute) + { + return switch (name) + { + case FormFields.MAX_FIELDS_ATTRIBUTE -> + { + int oldValue = getMaxFormKeys(); + if (attribute == null) + setMaxFormKeys(DEFAULT_MAX_FORM_KEYS); + else + setMaxFormKeys(Integer.parseInt(attribute.toString())); + yield oldValue; + } + case FormFields.MAX_LENGTH_ATTRIBUTE -> + { + int oldValue = getMaxFormContentSize(); + if (attribute == null) + setMaxFormContentSize(DEFAULT_MAX_FORM_CONTENT_SIZE); + else + setMaxFormContentSize(Integer.parseInt(attribute.toString())); + yield oldValue; + } + default -> super.setAttribute(name, attribute); + }; + } } private class CoreToNestedHandler extends Abstract diff --git a/jetty-ee9/jetty-ee9-webapp/src/main/java/org/eclipse/jetty/ee9/webapp/WebAppContext.java b/jetty-ee9/jetty-ee9-webapp/src/main/java/org/eclipse/jetty/ee9/webapp/WebAppContext.java index 7ccf48b9e25..eb028398e2f 100644 --- a/jetty-ee9/jetty-ee9-webapp/src/main/java/org/eclipse/jetty/ee9/webapp/WebAppContext.java +++ b/jetty-ee9/jetty-ee9-webapp/src/main/java/org/eclipse/jetty/ee9/webapp/WebAppContext.java @@ -945,6 +945,8 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL dumpObjects(out, indent, Dumpable.named("environment", ContextHandler.ENVIRONMENT.getName()), + Dumpable.named("maxFormKeys ", getMaxFormKeys()), + Dumpable.named("maxFormContentSize ", getMaxFormContentSize()), new ClassLoaderDump(getClassLoader()), new DumpableCollection("Systemclasses " + name, systemClasses), new DumpableCollection("Serverclasses " + name, serverClasses),