Serialization Filters - Sip of Java
Billy Korando on October 14, 2021Serialization 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!