How to validate an object before deserializing

24,439

Solution 1

Take a look at the ValidatingObjectInputStream. Basically you whitelist the classes that you will allow to be deserialized (you should know these based on the info you are pulling in). The validator will then check the metadata to the serialized data and reject any classes that are not within the whitelist.

Solution 2

If you look at the tips portion from the recommendations it states that the issue will be reported even if a look-ahead ObjectInputStream is implemented. Therefore even if you were able to fix the issue, you will not get rid of the finding.

However, it looks like your code is using JMS and with JMS, you do not control the deserialization. This is recognized by the recommendations you copied and pasted:

When deserialization takes place in library, or framework (e.g. when using JMX, RMI, JMS, HTTP Invokers) the above recommendation is not useful since it is beyond the developer's control. In those cases, you may want to make sure that these protocols meet the following requirements:

  • Not exposed publicly.
  • Use authentication.
  • Use integrity checks.
  • Use encryption.

Therefore, your true fix is to ensure those four bullet points are followed. You will have to do research into your connection and, depending on your requirements and limitations, that may not be possible.

Solution 3

In case anyone visits this old post, I got around this issue by switching from ObjectMessage to TextMessage and just sending JSON instead of serialized objects.

This post was very informative

//Sender
      ObjectMapper mapper = new ObjectMapper();
      TextMessage message = session.createTextMessage(mapper.writeValueAsString(foo));
      messageBus.send(message);

//Receiver
    ObjectMapper mapper = new ObjectMapper();
    try {
        Foobar foo= mapper.readValue(textMessage.getText(), new TypeReference<Foobar>(){});
        dataHandlerProcess(foo);
    } catch (IOException e) {
        logger.error("Could not parse Foobar JSON ",e );
        return;
    }
Share:
24,439
Tech Noob
Author by

Tech Noob

Updated on March 02, 2020

Comments

  • Tech Noob
    Tech Noob about 4 years

    In my code, I am calling getObject() method from an ObjectMessage object received from a JMS queue. Fortify report is complaining about this getObject() method with an error name like this Dynamic Code Evaluation: Unsafe Deserialization. Basically it says, I should not deserialize untrusted data without validating the contents of the object stream. Below is the code. How and what methods I should be using to get rid of this Fortify report error please.

    if (message instanceof ObjectMessage) {
        ObjectMessage objMessage = (ObjectMessage) message;
        Object objReportMessage = objMessage.getObject();
    ....
    

    Here is the Fortify reported issue with recommendations. Then it points this error to the code above at the line objMessage.getObject();

    Dynamic Code Evaluation: Unsafe Deserialization (1 issue)

    Abstract Deserializing user-controlled object streams at runtime can allow attackers to execute arbitrary code on the server, abuse application logic or lead to denial of service.

    Explanation Java serialization turns object graphs into byte streams containing the objects themselves and the necessary metadata to reconstruct them from the byte stream. Developers can create custom code to aid in the process of deserializing Java objects, where they may even replace the deserialized objects with different objects, or proxies. The customized deserialization process takes place during objects reconstruction before the objects are returned to the application and cast into expected types. By the time developers try to enforce an expected type, code may have already been executed. Custom deserialization routines are defined in the serializable classes which need to be present in the runtime classpath and cannot be injected by the attacker so the exploitability of these attacks depends on the classes available in the application environment. Unfortunately, common third party classes or even JDK classes can be abused to exhaust JVM resources, deploy malicious files, or run arbitrary code. Certain protocols use Java serialization behind the scenes in the transport layer. RMI and JMX are examples of these protocols.

    Example 1: Here is an example of an RMI interface that can be exposed publicly, containing methods with one or more parameters. When invoking these methods remotely, the arguments will be deserialized on the server allowing attackers to inject malicious object graphs.

    public interface MyService extends java.rmi.Remote {
    public Object doSomething (Object arg0) throws RemoteException;
    public Object doSomethingElse (Object arg0, Object arg1) throws
    RemoteException;
    ...
    }
    

    Example 2: JMX MBeans also use Java serialization to transmit call arguments. In the example below, the MyManagedBean class methods will be exposed to clients.

    MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
    ObjectName name = new ObjectName("com.example:type=MyManagedBean");
    MyManagedBean mbean = new MyManagedBean();
    mbs.registerMBean(mbean, name);
    

    Recommendation If possible, do not deserialize untrusted data without validating the contents of the object stream. In order to validate classes being deserialized, the look-ahead deserialization pattern should be used. The object stream will first contain the class description metadata and then the serialized bytes of their member fields. The Java serialization process allows developers to read the class description and decide whether to proceed with the deserialization of the object or abort it. In order to do so, it is necessary to subclass java.io.ObjectInputStream and provide a custom implementation of the resolveClass(ObjectStreamClass desc) method where class validation and verification should Sep 29, 2016, 5:09 PM Copyright 2015 Hewlett Packard Enterprise Development LP 13 take place. There are existing implementations of the look-ahead pattern that can be easily used, such as the Apache Commons IO (org.apache.commons.io.serialization.ValidatingObjectInputStream). Always use a strict whitelist approach to only deserialize expected types. A blacklist approach is not recommended since attackers can use many available gadgets to bypass the blacklist. Also, keep in mind that although some classes to achieve code execution are publicly known, there may be others that are unknown or undisclosed, so a whitelist approach will always be preferred. Any class allowed in the whitelist should be audited to make sure it is safe to deserialize. To avoid denial of service attacks, it is recommended that you override the resolveObject(Object obj) method in order to count how many objects are being deserialized and abort the deserialization when a threshold is surpassed. When deserialization takes place in library, or framework (e.g. when using JMX, RMI, JMS, HTTP Invokers) the above recommendation is not useful since it is beyond the developer's control. In those cases, you may want to make sure that these protocols meet the following requirements: - Not exposed publicly. - Use authentication. - Use integrity checks. - Use encryption. In addition, HPE Security Fortify Runtime provides security controls to be enforced every time the application performs a deserialization from an ObjectInputStream, protecting both application code but also library and framework code from this type of attack.