Add documentation for form limits & improve configuration via context attributes

Signed-off-by: Lachlan Roberts <lachlan.p.roberts@gmail.com>
This commit is contained in:
Lachlan Roberts 2024-09-04 16:45:53 +10:00
parent 165327a1bf
commit 190d441e1e
No known key found for this signature in database
GPG Key ID: 5663FB7A8FF7E348
9 changed files with 205 additions and 1 deletions

View File

@ -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[]
}
}

View File

@ -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[]

View File

@ -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+]
----
<Configure class="org.eclipse.jetty.{ee-current}.webapp.WebAppContext">
...
<Set name="maxFormContentSize">200000</Set>
<Set name="maxFormKeys">200</Set>
</Configure>
----
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`.

View File

@ -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

View File

@ -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),

View File

@ -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

View File

@ -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),

View File

@ -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

View File

@ -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),