Avoid Java Serialization!

Avatar
Brian Vermeer

Developer Advocate and Software Engineer for Snyk. Passionate about Java, (Pure) Functional Programming, and Cybersecurity. Co-leading the Virtual JUG, Utrecht JUG and DevSecCon community. Brian is also an Oracle Groundbreaker Ambassador and regular international speaker on mostly Java-related conferences

Serialization in Java allows us to transform an object to a byte stream. This byte stream is either saved to disk or transported to another system. The other way around, a byte stream can be deserialized and allows us to recreate the original object.

The biggest problem is with the deserializing part. Typically it looks something like this:

ObjectInputStream in = new ObjectInputStream( inputStream );
return (Data)in.readObject();

There’s no way to know what you’re deserializing before you decoded it. Possibly, an attacker serialized a malicious object and sent it to your application. Once you call readObject(), the malicious objects have already been instantiated. You might believe that these kinds of attacks are impossible because you need to have a vulnerable class on you classpath. However, if you consider the amount of classes on your classpath—that includes your own code, Java libraries, third-party libraries and frameworks—it is very likely that there is a vulnerable class available.

Java serialization is also called “the gift that keeps on giving” because of the many problems it has produced over the years. Oracle is planning to eventually remove Java serialization as part of Project Amber. However, this may take a while, and it’s unlikely to be fixed in previous versions. Therefore, it is wise to avoid Java serialization as much as possible. If you need to implement serializable on your domain entities, it is best to implement its own readObject(), as seen below. This prevents deserialization.

private final void readObject(ObjectInputStream in) throws java.io.IOException {
   throw new java.io.IOException("Deserialized not allowed");
}

If you need to Deserialize an inputstream yourself, you should use an ObjectsInputStream with restrictions. A nice example of this is the ValidatingObjectInputStream from Apache Commons IO. This ObjectInputStream checks whether the object that is deserialized, is allowed or not.

FileInputStream fileInput = new FileInputStream(fileName);
ValidatingObjectInputStream in = new ValidatingObjectInputStream(fileInput);
in.accept(Foo.class);

Foo foo_ = (Foo) in.readObject();

Object deserialization problems are not restricted to Java serialization. Deserialization from JSON to Java Object can contain similar problems. An example of such a deserialization issue with the Jackson library is in the blog post “Jackson Deserialization Vulnerability”.

This was just 1 of 10 Java security best practices. Take a look at the full 10 and the easy printable one-pager available.

Topics:

Don’t Forget to Share This Post!

Comments (0)

Your email address will not be published. Required fields are marked *

Highlight your code snippets using [code lang="language name"] shortcode. Just insert your code between opening and closing tag: [code lang="java"] code [/code]. Or specify another language.

Related Articles

Subscribe to foojay updates:

https://foojay.io/feed/
Copied to the clipboard