2 Serialization Filtering
You can use the Java serialization filtering mechanism to help prevent deserialization vulnerabilities. You can define pattern-based filters or you can create custom filters.
Addressing Deserialization Vulnerabilities
An application that accepts untrusted data and deserializes it is vulnerable to attacks. You can create filters to screen incoming streams of serialized objects before they are deserialized.
Inherent Dangers of Deserialization
Deserializing untrusted data, especially from an unknown, untrusted, or unauthenticated client, is an inherently dangerous activity because the content of the incoming data stream determines the objects that are created, the values of their fields, and the references between them. By careful construction of the stream, an adversary can run code in arbitrary classes with malicious intent.
For example, if object construction has side effects that change state or invoke other actions, then those actions can compromise the integrity of application objects, library objects, and even the Java runtime. "Gadget classes," which can perform arbitrary reflective actions such as create classes and invoke methods on them, can be deserialized maliciously to cause a denial of service or remote code execution.
The key to disabling deserialization attacks is to prevent instances of arbitrary classes from being deserialized, thereby preventing the direct or indirect execution of their methods. You can do this through serialization filters.
Java Serialization and Deserialization Overview
An object is serialized when its state is converted to a byte stream. That stream can be sent to a file, to a database, or over a network. A Java object is serializable if its class or any of its superclasses implements either the java.io.Serializable interface or the java.io.Externalizable subinterface. In the JDK, serialization is used in many areas, including Remote Method Invocation (RMI), custom RMI for interprocess communication (IPC) protocols (such as the Spring HTTP invoker), and Java Management Extensions (JMX).
An object is deserialized when its serialized form is converted to a copy of the object. It is important to ensure the security of this conversion. Deserialization is code execution because the readObject method of the class that is being deserialized can contain custom code.
Serialization Filters
A serialization filter enables you to specify which classes are acceptable to an application and which should be rejected. Filters also enable you to control the object graph size and complexity during deserialization so that the object graph doesn’t exceed reasonable limits. You can configure filters as properties or implement them programmatically.
Note:
A serialization filter is not enabled or configured by default. Serialization filtering doesn't occur unless you have specified the filter in a system property or a Security Property or set it with the ObjectInputFilter class.- Do not deserialize untrusted data.
- Use SSL to encrypt and authenticate the connections between applications.
- Validate field values before assignment, for example, checking object invariants by using the readObject method.
Note:
Built-in filters are provided for RMI. However, you should use these built-in filters as starting points only. Configure reject-lists and/or extend the allow-list to add additional protection for your application that uses RMI. See Built-in Filters.For more information about these and other strategies, see "Serialization and Deserialization" in Secure Coding Guidelines for Java SE.
Java Serialization Filters
The Java serialization filtering mechanism screens incoming streams of serialized objects to help improve security and robustness. Filters can validate incoming instances of classes before they are deserialized.
-
Provide a way to narrow the classes that can be deserialized down to a context-appropriate set of classes.
-
Provide metrics to the filter for graph size and complexity during deserialization to validate normal graph behaviors.
-
Allow RMI-exported objects to validate the classes expected in invocations.
There are two kinds of filters:
- JVM-wide filter: Is applied to every deserialization in the JVM. However, whether and how a JVM-wide filter validates classes in a particular deserialization depends on how it's combined with other filters.
- Stream-specific filter: Validates classes from one specific
ObjectInputStream
.
You can implement a serialization filter in the following ways:
-
Specify a JVM-wide, pattern-based filter with the
jdk.serialFilter
property: A pattern-based filter consists of a sequence of patterns that can accept or reject the name of specific classes, packages, or modules. It can place limits on array sizes, graph depth, total references, and stream size. A typical use case is to add classes that have been identified as potentially compromising the Java runtime to a reject-list. If you specify a pattern-based filter with thejdk.serialFilter
property, then you don't have to modify your application. -
Implement a custom or pattern-based stream-specific filter with the
ObjectInputFilter
API: You can implement a filter with the ObjectInputFilter API, which you then set on an ObjectInputStream. You can create a pattern-based filter with theObjectInputFilter
API by calling theConfig.createFilter(String)
method.
Note:
A serialization filter is not enabled or configured by default. Serialization filtering doesn't occur unless you have specified the filter in a system property or a Security Property or set it with the ObjectInputFilter class.For every new object in the stream, the filter mechanism applies only one filter to it. However, this filter might be a combination of filters.
In most cases, a stream-specific filter should check if a JVM-wide filter is set,
especially if you haven't specified a filter factory. If a JVM-wide filter does exist,
then the stream-specific filter should invoke it and use the JVM-wide filter’s result
unless the status is UNDECIDED
.
Filter Factories
A filter factory selects, chooses, or combines filters into a single filter to be used for a stream. When you specify one, a deserialization operation uses it when it encounters a class for the first time to determine whether to allow it. (Subsequent instances of the same class aren't filtered.) It's implemented as a BinaryOperator<ObjectInputFilter> and specified with the ObjectInputFilter.Config.setSerialFilterFactory method or in a system or Security property; see Setting a Filter Factory. Whenever an ObjectInputStream is created, the filter factory selects an ObjectInputFilter. However, you can have a different filter created based on the characteristics of the stream and the filter that the filter factory previously created.
Allow-Lists and Reject-Lists
Allow-lists and reject-lists can be implemented using pattern-based filters or custom filters. These lists allow you to take proactive and defensive approaches to protect your applications.
The proactive approach uses allow-lists to allow only class names that are recognized and trusted and to reject all others. You can implement allow-lists in your code when you develop your application, or later by defining pattern-based filters. If your application only deals with a small set of classes then this approach can work very well. You can implement allow-lists by specifying the names of classes, packages, or modules that are allowed.
The defensive approach uses reject-lists to reject instances of classes that are not
trusted. Usually, reject-lists are implemented after an attack that reveals that a class
is a problem. A class name can be added to a reject-list, without a code change, by
adding it to a pattern-based filter that's specified in the
jdk.serialFilter
property.
Creating Pattern-Based Filters
Pattern-based filters are filters that you define without changing your
application code. You add JVM-wide filters in properties files or application-specific
filters on the java
command line.
A pattern-based filter is a sequence of patterns. Each pattern is matched against the name of a class in the stream or a resource limit. Class-based and resource limit patterns can be combined in one filter string, with each pattern separated by a semicolon (;).
Pattern-based Filter Syntax
-
Separate patterns by semicolons. For example:
pattern1.*;pattern2.*
-
White space is significant and is considered part of the pattern.
-
Put the limits first in the string. They are evaluated first regardless of where they are in the string, so putting them first reinforces the ordering. Otherwise, patterns are evaluated from left to right.
-
A class name that matches a pattern that is preceded by
!
is rejected. A class name that matches a pattern without!
is allowed. The following filter rejectspattern1.MyClass
but allowspattern2.MyClass
:!pattern1.*;pattern2.*
-
Use the wildcard symbol (
*
) to represent unspecified class names in a pattern as shown in the following examples:-
To match every class name, use
*
-
To match every class name in
mypackage
, usemypackage.*
-
To match every class name in
mypackage
and its subpackages, usemypackage.**
-
To match every class name that starts with
text
, usetext*
-
If a class name doesn’t match any filter, then it is allowed. If you want to allow
only certain class names, then your filter must reject everything that doesn’t
match. To reject all class names other than those specified, include
!*
as the last pattern in a class filter.
For a complete description of the syntax for the patterns, see JEP 290.
Pattern-Based Filter Limitations
The following are some of the limitations of pattern-based filters:
-
Patterns can’t allow different sizes of arrays based on the class name.
-
Patterns can’t match classes based on the supertype or interfaces of the class name.
-
Patterns have no state and can’t make choices depending on the class instances deserialized earlier in the stream.
Note:
A pattern-based filter doesn't check interfaces that are implemented by classes being deserialized. The filter is invoked for interfaces explicitly referenced in the stream; it isn't invoked for interfaces implemented by classes for objects being deserialized.Define a Pattern-Based Filter for One Application
You can define a pattern-based filter as a system property for one application. A system property supersedes a Security Property value.
To create a filter that only applies to one application, and only to a single invocation of Java, define the jdk.serialFilter
system property in the command line.
The following example shows how to limit resource usage for an individual application:
java -Djdk.serialFilter=maxarray=100000;maxdepth=20;maxrefs=500 com.example.test.Application
Define a Pattern-Based Filter for All Applications
You can define a pattern-based, JVM-wide filter that affects every application run
with a Java runtime from $JAVA_HOME
by specifying it as a Security
Property. (Note that a system property supersedes a Security Property value.) Edit
the file $JAVA_HOME/conf/security/java.security
and add the
pattern-based filter to the jdk.serialFilter
Security
Property.
Define a Class Filter
You can create a pattern-based class filter that is applied globally. For example, the pattern might be a class name or a package with wildcard.
!example.somepackage.SomeClass
), and allows all other class
names in the package:
jdk.serialFilter=!example.somepackage.SomeClass;example.somepackage.*;
example.somepackage.*
. To reject all other class names, add
!*
:jdk.serialFilter=!example.somepackage.SomeClass;example.somepackage.*;!*
Define a Resource Limit Filter
-
Maximum allowed array size. For example:
maxarray=100000;
-
Maximum depth of a graph. For example:
maxdepth=20;
-
Maximum references in a graph between objects. For example:
maxrefs=500;
-
Maximum number of bytes in a stream. For example:
maxbytes=500000;
Creating Custom Filters
Custom filters are filters you specify in your application’s code. They are set on an individual stream or on all streams in a process. You can implement a custom filter as a pattern, a method, a lambda expression, or a class.
Reading a Stream of Serialized Objects
You can set a custom filter on one ObjectInputStream
, or, to
apply the same filter to every stream, set a JVM-wide filter. If an
ObjectInputStream
doesn’t have a filter defined for it, the JVM-wide
filter is called, if there is one.
While the stream is being decoded, the following actions occur:
- For each new object in the stream and before the object is instantiated and deserialized, the filter is called when it encounters a class for the first time. (Subsequent instances of the same class aren't filtered.)
- For each class in the stream, the filter is called with the resolved class. It is called separately for each supertype and interface in the stream.
- The filter can examine each class referenced in the stream, including the class of objects to be created, supertypes of those classes, and their interfaces.
- For each array in the stream, whether it is an array of primitives, array of strings, or array of objects, the filter is called with the array class and the array length.
- For each reference to an object already read from the stream, the filter is called so it can check the depth, number of references, and stream length. The depth starts at 1 and increases for each nested object and decreases when each nested call returns.
- The filter is not called for primitives or for java.lang.String instances that are encoded concretely in the stream.
- The filter returns a status of accept, reject, or undecided.
- Filter actions are logged if logging is enabled.
Unless a filter rejects the object, the object is accepted.
Setting a Custom Filter for an Individual Stream
You can set a filter on an individual ObjectInputStream when the input to the stream is untrusted and the filter has a limited set of classes or constraints to enforce. For example, you could ensure that a stream only contains numbers, strings, and other application-specified types.
A custom filter is set using the setObjectInputFilter method. The custom filter must be set before objects are read from the stream.
In the following example, the setObjectInputFilter method is invoked with the
dateTimeFilter
method. This filter only accepts classes from the
java.time package. The
dateTimeFilter
method is defined in a code sample in Setting a Custom Filter as a Method.
LocalDateTime readDateTime(InputStream is) throws IOException {
try (ObjectInputStream ois = new ObjectInputStream(is)) {
ois.setObjectInputFilter(FilterClass::dateTimeFilter);
return (LocalDateTime) ois.readObject();
} catch (ClassNotFoundException ex) {
IOException ioe = new StreamCorruptedException("class missing");
ioe.initCause(ex);
throw ioe;
}
}
Setting a JVM-Wide Custom Filter
You can set a JVM-wide filter that applies to every use of ObjectInputStream unless it is overridden on a specific stream. If you can identify every type and condition that is needed by the entire application, the filter can allow those and reject the rest. Typically, JVM-wide filters are used to reject specific classes or packages, or to limit array sizes, graph depth, or total graph size.
A JVM-wide filter is set once using the methods of the ObjectInputFilter.Config class. The filter can be an instance of a class, a lambda expression, a method reference, or a pattern.
ObjectInputFilter filter = ...
ObjectInputFilter.Config.setSerialFilter(filter);
In the following example, the JVM-wide filter is set by using a lambda expression.
ObjectInputFilter.Config.setSerialFilter(
info -> info.depth() > 10 ? Status.REJECTED : Status.UNDECIDED);
In the following example, the JVM-wide filter is set by using a method reference:
ObjectInputFilter.Config.setSerialFilter(FilterClass::dateTimeFilter);
Setting a Custom Filter Using a Pattern
A pattern-based custom filter, which is convenient for simple cases, can be created by using the ObjectInputFilter.Config.createFilter method. You can create a pattern-based filter as a system property or Security Property. Implementing a pattern-based filter as a method or a lambda expression gives you more flexibility.
The filter patterns can accept or reject specific names of classes, packages, and modules and can place limits on array sizes, graph depth, total references, and stream size. Patterns cannot match the names of the supertype or interfaces of the class.
example.File
and
rejects
example.Directory
.ObjectInputFilter filesOnlyFilter =
ObjectInputFilter.Config.createFilter("example.File;!example.Directory");
example.File
. All other class names
are
rejected.ObjectInputFilter filesOnlyFilter =
ObjectInputFilter.Config.createFilter("example.File;!*");
Setting a Custom Filter as a Class
A custom filter can be implemented as a class implementing the java.io.ObjectInputFilter interface, as a lambda expression, or as a method.
A filter is typically stateless and performs checks solely on the input
parameters. However, you may implement a filter that, for example, maintains state
between calls to the checkInput
method to count artifacts in the
stream.
In the following example, the FilterNumber
class allows any
object that is an instance of the Number
class and rejects all
others.
class FilterNumber implements ObjectInputFilter {
public Status checkInput(FilterInfo filterInfo) {
Class<?> clazz = filterInfo.serialClass();
if (clazz != null) {
return (Number.class.isAssignableFrom(clazz))
? ObjectInputFilter.Status.ALLOWED
: ObjectInputFilter.Status.REJECTED;
}
return ObjectInputFilter.Status.UNDECIDED;
}
}
In the example:
- The
checkInput
method accepts anObjectInputFilter.FilterInfo
object. The object’s methods provide access to the class to be checked, array size, current depth, number of references to existing objects, and stream size read so far. - If
serialClass
is not null, then the value is checked to see if the class of the object isNumber
. If so, it is accepted and returnsObjectInputFilter.Status.ALLOWED
. Otherwise, it is rejected and returnsObjectInputFilter.Status.REJECTED
. - Any other combination of arguments returns
ObjectInputFilter.Status.UNDECIDED
. Deserialization continues, and any remaining filters are run until the object is accepted or rejected. If there are no other filters, the object is accepted.
Setting a Custom Filter as a Method
A custom filter can also be implemented as a method. The method reference is used instead of an inline lambda expression.
The dateTimeFilter
method that is defined in the following
example is used by the code sample in Setting a Custom Filter for an Individual Stream.
public class FilterClass {
static ObjectInputFilter.Status dateTimeFilter(ObjectInputFilter.FilterInfo info) {
Class<?> serialClass = info.serialClass();
if (serialClass != null) {
return serialClass.getPackageName().equals("java.time")
? ObjectInputFilter.Status.ALLOWED
: ObjectInputFilter.Status.REJECTED;
}
return ObjectInputFilter.Status.UNDECIDED;
}
}
This custom filter allows only the classes found in the base module of the JDK:
static ObjectInputFilter.Status baseFilter(ObjectInputFilter.FilterInfo info) {
Class<?> serialClass = info.serialClass();
if (serialClass != null) {
return serialClass.getModule().getName().equals("java.base")
? ObjectInputFilter.Status.ALLOWED
: ObjectInputFilter.Status.REJECTED;
}
return ObjectInputFilter.Status.UNDECIDED;
}
Creating a Filter with ObjectInputFilter Methods
The ObjectInputFilter
interface includes the following
static methods that enable you to quickly create filters:
- allowFilter(Predicate<Class<?>>, ObjectInputFilter.Status)
- rejectFilter(Predicate<Class<?>>, ObjectInputFilter.Status)
- rejectUndecidedClass(ObjectInputFilter)
- merge(ObjectInputFilter, ObjectInputFilter)
The allowFilter method creates a filter based
on a Predicate
that takes a Class
as its argument. The
created filter returns ObjectInputFilter.Status.ALLOWED
if the
predicate is true. Otherwise, it returns the value of the allowFilter
method’s second argument. The following creates a filter that accepts the
Integer
class. All other classes are considered undecided:
ObjectInputFilter intFilter = ObjectInputFilter.allowFilter(
cl -> cl.equals(Integer.class), ObjectInputFilter.Status.UNDECIDED);
The rejectFilter method is the inverse of
allowFilter
: It creates a filter based on a Predicate that takes a Class as its
argument. The created filter returns ObjectInputFilter.Status.REJECTED if the predicate is true. Otherwise, it
returns the value of the rejectFilter method’s second
argument. The following creates a filter that rejects any class loaded from the
application class loader:
ObjectInputFilter f = ObjectInputFilter.rejectFilter(cl ->
cl.getClassLoader() == ClassLoader.getSystemClassLoader(), Status.UNDECIDED);
The rejectUndecidedClass
method creates a new filter based
on an existing filter by rejecting any class that the existing filter considers as
undecided. The following creates a filter based on intFilter
. It
accepts the Integer
class but rejects all other (undecided) classes:
ObjectInputFilter rejectUndecidedFilter =
ObjectInputFilter.rejectUndecidedClass(intFilter);
The merge
method creates a new filter by merging two
filters. The following merges the filters intFilter
and
f
. It accepts the Integer
class but rejects any
class loaded from the application class loader:
ObjectInputFilter mergedFilter = ObjectInputFilter.merge(intFilter, f);
A merged filter follows these steps when it filters a class:
- Return Status.REJECTED if either of its filters return Status.REJECTED.
- Return Status.ACCEPTED if either of its filters return Status.ACCEPTED.
- Return Status.UNDECIDED (both of its filters return Status.UNDECIDED).
The merge
method is useful in filter factories. Every time
a filter is set on a stream, you can append that filter to the one that the filter
factory creates with the merge
method. See the ObjectInputFilter
API documentation for an example.
Note:
It's a good idea to merge the JVM-wide filter with the requested, stream-specific filter in your filter factory. If you just return the requested filter, then you effectively disable the JVM-wide filter, which will lead to security gaps.Setting a Filter Factory
A filter factory is a BinaryOperator, which is a function of two operands that chooses the filter for a stream. You can set a filter factory by calling the method ObjectInputFilter.Config.setSerialFilterFactory or specifying it in a system or Security property.
Note:
You can set a filter factory exactly once, either with the method setSerialFilterFactory, in the system propertyjdk.serialFilterFactory
, or in the Security
Property jdk.serialFilterFactory
.
Setting a Filter Factory with setSerialFilterFactory
When you set a filter factory by calling the method ObjectInputFilter.Config.setSerialFilterFactory, the filter factory's method
BinaryOperator<ObjectInputFilter>.apply(ObjectInputFilter t,
ObjectInputFilter u)
will be invoked when an ObjectInputStream
is constructed and when a stream-specific filter is set on an
ObjectInputStream
. The parameter t
is the current
filter and u
is the requested filter. When apply is first invoked, t
will be null. If a JVM-wide filter
has been set, then when apply is first invoked,
u
will be the JVM-wide filter. Otherwise, u
will be
null. The apply method (which you must implement yourself)
returns the filter to be used for the stream. If apply is
invoked again, then the parameter t
will be this returned filter. When you
set a filter with the method ObjectInputStream.setObjectInputFilter(ObjectInputFilter), then parameter
u
will be this filter.
The following example implements a simple filter factory that prints its
ObjectInputFilter parameters every time its
apply
method is invoked, merges these parameters into one combined
filter, then returns this merged filter.
public class SimpleFilterFactory {
static class MySimpleFilterFactory implements BinaryOperator<ObjectInputFilter> {
public ObjectInputFilter apply(
ObjectInputFilter curr, ObjectInputFilter next) {
System.out.println("Current filter: " + curr);
System.out.println("Requested filter: " + next);
return ObjectInputFilter.merge(next, curr);
}
}
private static byte[] createSimpleStream(Object obj) {
ByteArrayOutputStream boas = new ByteArrayOutputStream();
try (ObjectOutputStream ois = new ObjectOutputStream(boas)) {
ois.writeObject(obj);
return boas.toByteArray();
} catch (IOException ioe) {
ioe.printStackTrace();
}
throw new RuntimeException();
}
public static void main(String[] args) throws IOException {
// Set a filter factory
MySimpleFilterFactory contextFilterFactory = new MySimpleFilterFactory();
ObjectInputFilter.Config.setSerialFilterFactory(contextFilterFactory);
// Set a stream-specific filter
ObjectInputFilter filter1 =
ObjectInputFilter.Config.createFilter("example.*;java.base/*;!*");
ObjectInputFilter.Config.setSerialFilter(filter1);
// Create another filter
ObjectInputFilter intFilter = ObjectInputFilter.allowFilter(
cl -> cl.equals(Integer.class), ObjectInputFilter.Status.UNDECIDED);
// Create input stream
byte[] intByteStream = createSimpleStream(42);
InputStream is = new ByteArrayInputStream(intByteStream);
ObjectInputStream ois = new ObjectInputStream(is);
ois.setObjectInputFilter(intFilter);
try {
Object obj = ois.readObject();
System.out.println("Read obj: " + obj);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
This example prints output similar to the following (line breaks have been added for clarity):
Current filter: null
Requested filter: example.*;java.base/*;!*
Current filter: example.*;java.base/*;!*
Requested filter:
merge(
predicate(
SimpleFilterFactory$$Lambda$8/0x0000000800c00c60@76ed5528,
ifTrue: ALLOWED, ifFalse: UNDECIDED),
predicate(
SimpleFilterFactory$$Lambda$9/0x0000000800c01800@2c7b84de,
ifTrue: REJECTED, ifFalse: UNDECIDED))
Read obj: 42
The apply
method is invoked twice: when the ObjectInputStream
ois
is created and when the method
setObjectInputFilter
is called.
Note:
- You can set a filter on an ObjectInputStream only once. An
IllegalStateException
will be thrown otherwise. - To protect against unexpected deserializations, ensure that security experts thoroughly review how your filter factories select and combine filters.
Specifying a Filter Factory in a System or Security Property
You can set a filter factory that applies to only one application and to only
a single invocation of Java by specifying it in the jdk.serialFilterFactory
system property in the command line:
java -Djdk.serialFilterFactory=FilterFactoryClassName
YourApplication
The value of jdk.serialFilterFactory
is the class name of
the filter factory to be set before the first deserialization. The class must be public
and accessible to the application class loader (which the method java.lang.ClassLoader.getSystemClassLoader()
returns).
You can set a JVM-wide filter factory that affects every application run
with a Java runtime from $JAVA_HOME
by specifying it in a Security
Property. Note that a system property supersedes a Security Property value. Edit the
file $JAVA_HOME/conf/security/java.security
and specify the filter
factory's class name in the jdk.serialFilterFactory
Security
Property.
Built-in Filters
The Java Remote Method Invocation (RMI) Registry, the RMI Distributed Garbage Collector, and Java Management Extensions (JMX) all have filters that are included in the JDK. You should specify your own filters for the RMI Registry and the RMI Distributed Garbage Collector to add additional protection.
Filters for RMI Registry
Note:
Use these built-in filters as starting points only. Edit thesun.rmi.registry.registryFilter
system property to configure reject-lists and/or
extend the allow-list to add additional protection
for the RMI Registry. To protect the whole
application, add the patterns to the
jdk.serialFilter
global system
property to increase protection for other
serialization users that do not have their own
custom filters.
The RMI Registry has a built-in allow-list filter that allows objects to be bound in
the registry. It includes instances of the java.rmi.Remote
,
java.lang.Number
, java.lang.reflect.Proxy
,
java.rmi.server.UnicastRef
,
java.rmi.server.UID
,
java.rmi.server.RMIClientSocketFactory
, and
java.rmi.server.RMIServerSocketFactory
classes.
maxarray=1000000;maxdepth=20
Supersede the built-in filter by defining a filter using the sun.rmi.registry.registryFilter
system property with a pattern. If the filter that you define either accepts classes passed to the filter, or rejects classes or sizes, the built-in filter is not invoked. If your filter does not accept or reject anything, the built-filter is invoked.
Filters for RMI Distributed Garbage Collector
Note:
Use these built-in filters as starting points only. Edit thesun.rmi.transport.dgcFilter
system property to configure reject-lists and/or
extend the allow-list to add additional protection
for Distributed Garbage Collector. To protect the
whole application, add the patterns to the
jdk.serialFilter
global system
property to increase protection for other
serialization users that do not have their own
custom filters.
The RMI Distributed Garbage Collector has a built-in allow-list filter that accepts
a limited set of classes. It includes instances of
the java.rmi.server.ObjID
,
java.rmi.server.UID
,
java.rmi.dgc.VMID
, and
java.rmi.dgc.Lease
classes.
maxarray=1000000;maxdepth=20
Supersede the built-in filter by defining a filter using the sun.rmi.transport.dgcFilter
system property with a pattern. If the filter accepts classes passed to the filter, or rejects classes or sizes, the built-in filter is not invoked. If the superseding filter does not accept or reject anything, the built-filter is invoked.
Filters for JMX
Note:
Use these built-in filters as starting points only. Edit thecom.sun.management.jmxremote.serial.filter.pattern
management property to configure reject-lists and/or extend the allow-list to add
additional protection for JMX. To protect the whole application, add the patterns to
the jdk.serialFilter
global system property to increase protection
for other serialization users that do not have their own custom filters.
JMX has a built-in filter to limit a set of classes allowed to be sent as a
deserializing parameters over RMI to the server. That filter is disabled by default.
To enable the filter, define the
com.sun.management.jmxremote.serial.filter.pattern
management
property with a pattern.
The pattern must include the types that are allowed to be sent as parameters over
RMI to the server and all types that they depend on, plus
javax.management.ObjectName
and
java.rmi.MarshalledObject
types. For example, to limit the
allowed set of classes to Open MBean types and the types that they depend on, add
the following line to management.properties
file:
com.sun.management.jmxremote.serial.filter.pattern=java.lang.*;java.math.BigInteger;java.math.BigDecimal;java.util.*;javax.management.openmbean.*;javax.management.ObjectName;java.rmi.MarshalledObject;!*
Logging Filter Actions
You can turn on logging to record the initialization, rejections, and acceptances of calls to serialization filters. Use the log output as a diagnostic tool to see what's being deserialized, and to confirm your settings when you configure allow-lists and reject-lists.
When logging is enabled, filter actions are logged to the java.io.serialization logger.
To enable serialization filter logging, edit the $JDK_HOME/conf/logging.properties
file.
To log calls that are rejected, add
java.io.serialization.level = FINE
To log all filter results, add
java.io.serialization.level = FINEST