This article, an article in IBM Developerworks, describes how to prevent the deserialization of untrusted data input without using encryption and signature techniques. (Last updated in 2013.01.18)
Java serialization allows a developer to save a Java object in binary format in order to persist the object to a file or pass it on the network. Remote method call (RMI) uses serialization as a communication medium between the client and the server. Multiple security issues arise when a service receives binary data from the client and serializes the input data to construct the Java instance. This article focuses on one of the issues: the hacker may serialize an instance of another class and pass it to the service program. The service program then serializes the malicious object and is likely to cast the object as the legitimate type expected by the service, which will cause the exception to occur. However, this exception is too late to ensure data security. This article explains why and how to implement a secure serialization.
Vulnerable classes
It is not possible for your service program to deserialize objects of any class. Why not? The simple answer is that there may be vulnerable classes that hackers exploit in the classpath of the server side. These classes contain code that creates a denial of service (DOS) condition, or-in extreme cases-allows the hacker to inject arbitrary code.
You may believe in the possibility of such an attack, but consider that there are too many classes in the classpath of a typical server-side program that includes not only your own code, but also the Java Core Class library, the third party class library, and other middleware or library classes in the framework. In addition, the classpath may be altered during the life cycle of the application, or the classpath of the application may be modified in response to changes in the underlying operating environment. When attempting to exploit such vulnerabilities, the hacker can combine these operations into one piece by transferring multiple serialized objects.
I should stress that the service will not serialize a malicious object until the following conditions are met:
1. The class of the malicious object exists in the server-side classpath. It is impossible for a hacker to pass any serialized object of any class casually, because the application service may not be able to load the class.
2. A malicious object's class is either serializable or externalized. (That is, this class on the server side implements Java.io.Serializable or java.io.Externalizable)
In addition, by copying data directly from a serialized stream, the serialization operation produces the object tree without invoking the constructor, so it is not possible for the hacker to execute the Java code in the constructor for the serialized object class.
But there are other ways for hackers to execute code on the server side. Whenever the JVM serializes an object, it implements one of the following three methods, calling and executing the code in the method:
1. Method ReadObject (), when the standard serialization mechanism does not apply, developers generally use this method. For example, when you need to assign a value to a transient member variable.
2. Method Readresolve (), typically used to serialize a single instance object.
3. Method Readexternal () for Externalized objects.
So, if you have classes in your classpath that use the above methods, you have to realize that hackers may invoke these methods remotely. Such attacks have been used in the past to destroy the applet security sandbox, and the same attack technology can also be used for server-side applications.
Continue reading, and you will see how you can only allow the application service to deserialize the object of the class that it expects.
Java Serialization binary format
After an object has been serialized, the binary data will contain metadata (referring to information about the structure of the data, such as the name of the class, the number of members, and the type of the member), and the object data itself. I'll take a simple bicycle class as an example, as shown in Listing 1, which contains three member variables (Id,name and nbrwheels) and their corresponding set and get methods.
Listing 1. Bicycle class
Package Com.ibm.ba.scg.LookAheadDeserializer;
public class Bicycle implements java.io.Serializable {
private static final long Serialversionuid = 57541045411683207 30L;
private int id;
private String name;
private int nbrwheels;
public Bicycle (int ID, String name, int nbrwheels) {
this.id = ID;
this.name = name;
This.nbrwheels = Nbrwheels;
}
Public String GetName () {return
name;
}
public void SetName (String name) {
this.name = name;
}
public void setId (int id) {
this.id = ID;
}
public int getId () {return
ID;
}
public int getnbrwheels () {return
nbrwheels;
}
public void setnbrwheels (int nbrwheels) {
this.nbrwheels = nbrwheels;
}
}