# Insecure Deserialization
*Serialization* describes the process of writing in-memory code object to a binary form, typically for storage to disk or transmission across a network. *Deserialization* is the opposite process: transforming incoming binary data into an in-memory code object. If your code uses deserialization, you need to ensure it is not deserializing untrusted input: the presents an opportunity for an attacker to inject malicious code into your web-server at runtime.
## Serialization in Java
Java objects can be serialized into a stream of bytes using the `java.io.ObjectOutputStream` class. Most built-in Java classes are serializable, and you can customize how your own classes are serialized by implementing the `java.io.Serialazable` interface, and, if needs be, writing your own serialization code.
Serialization is used during *Remote Method Invocation* (RMI) calls, and provides an easy way to store data structures to disk for later us. However, if you unserialize data coming from an untrusted source – like binary data attached to an HTTP request – this gives an attacker an opportunity to inject malicious code directly into your Java runtime.
“`java public class DeserializationServlet extends HttpServlet { protected void service(HttpServletRequest request, HttpServletResponse response) throws IOException { try { ServletInputStream stream = request.getInputStream(); ObjectInputStream objectStream = new ObjectInputStream(stream);// This object is taken from an untrusted source and is potentially malicious. Object deserialized = objectStream.readObject(); } catch (ClassNotFoundException ex) {} } } “` |
## Mitigation
The easiest way to avoid deserialization vulnerabilities is to avoid using serialization altogether. If you need to accept structured data from an HTTP request, XML or JSON are more common formats and less prone to malicious use.
If you *do* use serialization, ensure your byte streams come from a trusted source, deserialize to an expected form, and cannot be tampered with. Your code should make assertions about the class of each object as it is deserialized, as a way of reducing the attack surface:
“`java ServletInputStream stream = request.getInputStream();// Restricting the classes we deserialize to reduces the risk. ObjectInputStream objectStream = new ObjectInputStream(stream) { protected Class<?> resolveClass(ObjectStreamClass osc) throws IOException, ClassNotFoundException { if (!osc.getName().equals(java.util.HashMap.class.getName())) { throw new InvalidClassException(“Unexpected class”, osc.getName()); }return super.resolveClass(osc); } }; Object deserialized = objectStream.readObject(); |
To detect tampering, you can generate a digital signature when you write out a byte stream for later use, then verify that signature when reading the objects back in:
“`java /** * Generate a digital signature for some binary data, so we can verify it has not * been tampered with if it is returned from an untrusted source. */ public static String signData(byte[] data) throws Exception { KeyPair keyPair = getKeyPair();Signature signature = Signature.getInstance(“SHA1WithRSA”); signature.initSign(keyPair.getPrivate()); signature.update(data);byte[] bytes = signature.sign(); return Base64.getEncoder().encodeToString(bytes); |
## CWEs
* [CWE-614](https://cwe.mitre.org/data/definitions/614)