Item 85: Prefer alternatives to Java serialization

85. Think of other ways than serializing in Java

Serialization is vulnerable

The fundamental problem with serialization is that the areas that can be attacked are too large and are constantly spreading. The object graph (an image of a group of objects connected by reference) is restored by the readObject method of ObjectInputStream. This method allows you to instantiate objects of almost any type on your classpath, as long as the type implements Serializable. In the process of deserializing the byte stream, this method can execute any type of code that is on the classpath and implements Serialize. Therefore, all these types are targeted for attack.

Gadgets, gadget chains

Even if you remove the vulnerability from a serializable class that can be attacked, the application itself may still be vulnerable. If you create a gadget chain by combining methods that can perform dangerous processing (called gadgets) from serializable type methods, sometimes it happens that arbitrary native code can be executed. In fact, in 2016, a hack using this mechanism was made against the San Francisco Metropolitan Transit Agency Municipal Railway.

Deserialization bomb

As mentioned above, you can easily create a stream that takes a lot of time to deserialize without using a gadget, and you can make a DoS attack with this. Such streams are called deserialization bombs.

// Deserialization bomb - deserializing this stream takes forever
static byte[] bomb() {
    Set<Object> root = new HashSet<>();
    Set<Object> s1 = root;
    Set<Object> s2 = new HashSet<>();
    for (int i = 0; i < 100; i++) {
        Set<Object> t1 = new HashSet<>();
        Set<Object> t2 = new HashSet<>();
        t1.add("foo"); // Make t1 unequal to t2
        s1.add(t1);  s1.add(t2);
        s2.add(t1);  s2.add(t2);
        s1 = t1;
        s2 = t2;
    }
    return serialize(root); // Method omitted for brevity
}

In the above code, there are 100 layers of structure in which one HashSet has two HashSet elements. When you create a HashSet instance, you have to calculate the hashcode for each element. Therefore, it is necessary to call hashCode 2 to the 100th power, and the processing is not completed at all.

What should I do?

How should we deal with the above attacks related to serialization?

Use other mechanisms

** The best way is not to deserialize. ** ** ** There is no reason to use Java serialization in new systems. ** ** There are better mechanisms for translating byte sequences and objects, which are called cross-platform structured-data representations.

JSON and Protobuf

Typical cross-platform structured-data representations are JSON and Protocol. The most important difference between JSON and Protobuf is that JSON is text-based and human-readable, while Protobuf is binary and more efficient.

Do not deserialize untrusted data

Serialization in Java may be unavoidable in the maintenance and development of legacy systems. In such cases, you should take measures such as ** do not deserialize untrusted data **. In particular, do not accept RMI traffic from untrusted sources.

Use the filtering function during deserialization

If serialization in Java is unavoidable and the safety of the deserializing data is questionable, the object deserialization filter java.io.ObjectInputFilter (introduced from Java 9 and backported to 6,7,8) ) Should be used. This provides the ability to filter the stream before it is deserialized. You can decide whether to reject or accept on a class-by-class basis. At this time, you can select either whitelist format or blacklist format, but since blacklists can only protect against known threats, whitelists should be adopted. The filtering feature also prevents excessive memory usage and excessively deep object graphs, but it does not prevent the deserialization bombs mentioned above.

Recommended Posts

Item 85: Prefer alternatives to Java serialization
Item 28: Prefer lists to arrays
Item 65: Prefer interfaces to reflection
Item 43: Prefer method references to lambdas
Java serialization
Item 42: Prefer lambdas to anonymous classes
Item 39: Prefer annotations to naming patterns
Item 58: Prefer for-each loops to traditional for loops
Item 23: Prefer class hierarchies to tagged classes
Item 61: Prefer primitive types to boxed primitives
[Java] Introduction to Java
Java serialization notes
Introduction to java
Item 81: Prefer concurrency utilities to wait and notify
Item 80: Prefer executors, tasks, and streams to threads
Item 89: For instance control, prefer enum types to readResolve
Changes from Java 8 to Java 11
Sum from Java_1 to 100
[Java] Connect to MySQL
Effective Java 3rd Edition Section 85 Choose Alternatives Over Java Serialization
Kotlin's improvements to Java
Java --Serialization and Deserialization
From Java to Ruby !!
Introduction to java command
Java Object Serialization why & when
[Java] How to use Map
How to lower java version
Migration from Cobol to JAVA
[Java] How to use Map
Convert Java Powerpoint to XPS
Java adds table to PDF
How to uninstall Java 8 (Mac)
Java to play with Function
Java --How to make JTable
How to use java Optional
New features from Java7 to Java8
How to minimize Java images
How to write java comments
[Java] How to use Optional ②
Connect from Java to PostgreSQL
[Java] How to use removeAll ()
[Java] Introduction to lambda expressions
[Java] How to use string.format
Shell to kill Java process
How to use Java Map
How to set Java constants
Connect to DB with Java
Connect to MySQL 8 with Java
[java] Reasons to use static
How to use Java variables
Json serialization / deserialization in Java 1.4
[Java] Introduction to Stream API
Java8 to start now ~ Optional ~
How to convert Java radix
[Java] Convert ArrayList to array
Java thread to understand loosely
[Java] How to implement multithreading
[Java] How to use Optional ①
From Ineffective Java to Effective Java
How to initialize Java array
[Introduction to rock-paper-scissors games] Java