Contents

Creating deserialization filters

Writen by: David Vlijmincx

Introduction

Prevent deserialization of unwanted objects with the ObjectInputFilter. In this post, we create three implements of a filter that we can use for the entire application and a single objectInputStream.

Creating a filter

A filter is created with a String of patterns, Method, or a Lambda expression and used by an ObjectInputStream to filter out objects that should not be deserialized.

Creating a filter with a string of patterns

Creating a filter with patterns is done with a String like this: "pattern1;patter2". The patterns in the String are separated with semicolons.

This is what the Java doc says about creating a pattern:

  • If the pattern starts with “!", the class is rejected if the remaining pattern is matched; otherwise, the class is allowed if the pattern matches.
  • If the pattern contains “/", the non-empty prefix up to the “/” is the module name; if the module name matches the module name of the class then the remaining pattern is matched with the class name. If there is no “/", the module name is not compared.
  • If the pattern ends with “.**” it matches any class in the package and all sub-packages.
  • If the pattern ends with “.*” it matches any class in the package.
  • If the pattern ends with “*", it matches any class with the pattern as a prefix.
  • If the pattern is equal to the class name, it matches.
  • Otherwise, the pattern is not matched.

Below we create a filter that only accepts classes from the package foo and nothing else.

1
var filter = ObjectInputFilter.Config.createFilter("foo*;!*");

Creating a filter with Lambda

Using a Lambda expression to create a filter, you gain more control over what objects are allowed to be deserialized. Below we create a filter that checks if the class name of the serialized object is equal to foo.Bar.

1
2
3
ObjectInputFilter objectInputFilter = filterInfo -> filterInfo.serialClass().getName().equals("foo.Bar") ?
        ObjectInputFilter.Status.ALLOWED :
        ObjectInputFilter.Status.REJECTED;

Or you can point to a method holding the logic using a method reference.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
// Inside a method where the objectInputStream is 
objectInputStream.setObjectInputFilter(this::objectFilter);

// Method holding the filter logic
ObjectInputFilter.Status objectFilter(ObjectInputFilter.FilterInfo filterInfo){

        if(filterInfo.serialClass().getName().equals("foo.Bar")){
            return ObjectInputFilter.Status.ALLOWED;
        }
        else {
            return ObjectInputFilter.Status.REJECTED;
        }
    }

Setting a filter for the entire application

The setSerialFilter method of the ObjectInputFilter.Config class sets a default filter for every ObjectInputStream that is going to be created.

We create a filter and set it to be the default:

1
2
var filter = ObjectInputFilter.Config.createFilter("foo*;!*");
ObjectInputFilter.Config.setSerialFilter(filter);

Setting a filter for a ObjectInputStream

The setObjectInputFilter sets a filter for the objectInputStream instance. If there is a filter set in ObjectInputFilter.Config it will also be used. Meaning that the filter in the ObjectInputFilter.Config and the filter of the objectInputStream both have to allow the object to be deserialized.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
var objectInputStream = new ObjectInputStream(inputStream);

// Using filter created with a String
var filter = ObjectInputFilter.Config.createFilter("!*");
objectInputStream.setObjectInputFilter(filter);

// Or as lambda
objectInputStream.setObjectInputFilter(filterInfo -> filterInfo.serialClass().getName().equals("foo.Bar") ?
        ObjectInputFilter.Status.ALLOWED :
        ObjectInputFilter.Status.REJECTED);

Concussion

Using a filter will help prevent deserialization vulnerabilities. Using a String of patterns is an easy way to create a filter. If you need more logic to decide what to deserialize, you can create your filters inside a lambda or method reference.

Sources and references

If you want to know more about filtering an ObjectInputStream: