javaspringspring-mvcsecurityfortify

Dynamic Code Evaluation: Unsafe Deserialization on SerializationUtils.clone()


I am getting Fortify issue Dynamic Code Evaluation: Unsafe Deserialization on the lines below:

@RequestMapping(value="/v2/doc", method=RequestMethod.POST)
    public JsonDocVerifyResponse verify(@RequestBody JsonDocVerifyRequestV3 request)

JsonDocVerifyRequestV3 temp = (JsonDocVerifyRequestV3)SerializationUtils.clone(request);

The solution for unsafe deserialization is this https://www.ibm.com/developerworks/library/se-lookahead/ But as you can see in my codes I am not using ByteArrayOutputStream to deserialize the object.

Is this a false positive by Fortify? If not, how can I use

org.apache.commons.io.serialization.ValidatingObjectInputStream

to validate the class? Any code sample will be of great help!

These are the snippets:

    @RequestMapping(value="/v2/doc", method=RequestMethod.POST)
    public JsonDocVerifyResponse verify(@RequestBody JsonDocVerifyRequestV3 request) {

        debugJsonRequest(request, DOC_TYPE.khIdBack);

        JsonDocVerifyResponse response = new JsonDocVerifyResponse();

        return response;
    }
   public void debugJsonRequest(JsonDocVerifyRequestV3 request, DOC_TYPE docType) {

        try {

          JsonDocVerifyRequestV3 temp(JsonDocVerifyRequestV3) SerializationUtils.clone(request);

          LOGGER.debug("{}|{}", docType, CommonUtil.debugJsonObject(temp));

        } catch(Exception e) {
         LOGGER.error("Error in debug json object", e);
        }

 }

Solution

  • You can use accept and reject methods to safer deserialization operation.

    Example:

    import com.sun.xml.internal.ws.util.ByteArrayBuffer;
    import org.apache.commons.io.serialization.ValidatingObjectInputStream;
    
    import java.io.*;
    
    public class Main {
        public static void main(String[] args) throws IOException, ClassNotFoundException {
            Bar bar = new Bar("bar-test");
            Foo foo = new Foo("test-foo", bar);
    
            // write into an array buffer
            ByteArrayBuffer buffer = new ByteArrayBuffer();
            try (ObjectOutputStream serializeStream = new ObjectOutputStream(buffer)) {
                serializeStream.writeObject(foo);
            }
    
            try (ValidatingObjectInputStream stream = new ValidatingObjectInputStream(buffer.newInputStream())) {
                // add validated classes
                stream.accept(Foo.class);
                stream.accept(Bar.class);
    
    
                Foo foo2 = (Foo) stream.readObject();
                System.out.println(foo2);
            }
        }
    
        public static class Foo implements Serializable {
            private String name;
            private Bar bar;
    
            public Foo(String name, Bar bar) {
                this.name = name;
                this.bar = bar;
            }
    
            @Override
            public String toString() {
                return "Foo{" +
                        "name='" + name + '\'' +
                        ", bar=" + bar +
                        '}';
            }
        }
    
        public static class Bar implements Serializable {
            private String name;
    
            public Bar(String name) {
                this.name = name;
            }
    
            @Override
            public String toString() {
                return "Bar{" +
                        "name='" + name + '\'' +
                        '}';
            }
        }
    }