Sip of Java - Serialization Filters

Serialization Filters were added in JDK 9 (see JEP 290) and updated in JDK 17 (see JEP 415). Serialization filters give Java applications more control over how incoming data is deserialized. Let’s look at why this matters and how to configure a serialization filter.

Issues with Serialization

Serialization in Java has long been a source of headaches relating to several issues with how it was implemented. A few of those issues include:

  • Breaks Encapsulation

  • Behavior Governed by “Magic” Fields and Methods: readObject, writeObject, readObjectNoData, readResolve, writeReplace, etc.

  • And more!

Filtering Serialized Data

Because of the implementations issues with serialization covered above, there are real risks to deserializing data, particularly untrusted data, which is covered in more detail here. A powerful tool for protecting your application against an unsecure deserialization attack is with serialization filtering.

Pattern Based Filtering

Filtering can be configured via a pattern which can filter based on:

  • Maximum depth of the object graph

  • Maximum references of the object graph

  • Maximum bytes of the object graph

  • Maximum array size

  • Allow or reject by type based on class name, package name or module name

Read here for how to construct a pattern.

Setting Pattern Based Filter as Security Property

A pattern based filter can be set as a security property by adding the jdk.serialFilterFactory like in the example below:

jdk.serialFilterFactory=<pattern>

To the file:

$JAVA_HOME/conf/security/java.security

Setting Pattern Based Filter as JVM Argument

A pattern based filter can also be set as a JVM arg like in the example below:

-Djdk.serialFilter=<pattern>

Configuring Filter in Code

A filter can also be configured as code as well.

Factory Filter

A factory method is available that can be used to create a filter by taking pattern:

ObjectInputFilter.Config.createFilter(String);

Implement Custom Filter

The interface ObjectInputFilter can also be implemented to provide more flexibility for filtering serialized data than what is possible with a pattern based filter:

class Filter implements ObjectInputFilter {

	@Override
	public Status checkInput(FilterInfo filterInfo) {
		...
		return null;
	}
	
}

Setting Filter in Code

A filter defined in code can be set at the JVM level or even at the individual stream level.

JVM-wide Filter

To set a fitler at the JVM wide level setSerialFilter like in the example below:

ObjectInputFilter.Config.setSerialFilter(ObjectInputFilter);

Individual Stream Level

To set a filter at the individual stream level, use setObjectInputFilter on the stream instance you want to be filtered:

ObjectInputStream.setObjectInputFilter(ObjectInputFilter);


Additional Reading


Happy Coding!