Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to use a custom ObjectInputStream for secure deserialization in Spring #26618

Closed
mattjerry opened this issue Feb 27, 2021 · 5 comments
Closed
Assignees
Labels
status: invalid An issue that we don't feel is valid

Comments

@mattjerry
Copy link

mattjerry commented Feb 27, 2021

Overview

Our tech stack is Spring, JPA using Hibernate, and SQL server.

  1. We use Jackson for JSON serialization/deserialization for REST implementation.
  2. In our model class - we have implements Serializable.
  3. Jackson ObjectMapper which Spring uses also implements Serializable.

As we can see, Hibernate has serialization which is binary (Java), and Jackson is text (JSON) based serialization.

We would like to harden all uses of ObjectInputStream of java and make sure that there are no deserialization issues in our application.

@jhoeller, we request your insights in building a hardened application.

Questions

  1. When spring and jpa/hibernate are implemented, does hibernate use the ConfigurableObjectInputStream?
  2. Does jackson use the ConfigurableObjectInputStream?
  3. How can we configure Spring to use our LookAheadObjectInputStream instead of ConfigurableObjectInputStream?

Custom ObjectInputStream

Inspired by an example from OWASP, we would like to define a LookAheadObjectInputStream which would extend Spring's ConfigurableObjectInputStream where we can define our own application classes that can be resolved.

public class LookAheadObjectInputStream extends ConfigurableObjectInputStream {

    public LookAheadObjectInputStream(InputStream inputStream) throws IOException {
        super(inputStream);
    }

   /**
    * Only deserialize instances of our expected Bicycle class
    */
    @Override
    protected Class<?> resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException {
        if (!desc.getName().equals(Bicycle.class.getName())) {
            throw new InvalidClassException("Unauthorized deserialization attempt", desc.getName());
        }
        return super.resolveClass(desc);
    }
}
@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged or decided on label Feb 27, 2021
@sbrannen sbrannen changed the title How to customize ConfigurableObjectInputStream and use extended LookAheadObjectInputStream How to use a custom ObjectInputStream for secure deserialization in Spring Feb 28, 2021
@sbrannen
Copy link
Member

I've edited your comment to improve the formatting. You might want to check out this Mastering Markdown guide for future reference.

@sbrannen sbrannen self-assigned this Mar 1, 2021
@sbrannen
Copy link
Member

sbrannen commented Mar 1, 2021

Let me start by answering your questions.

  • When spring and jpa/hibernate are implemented, does hibernate use the ConfigurableObjectInputStream?

No.

  • Does jackson use the ConfigurableObjectInputStream?

No. Jackson deserializes JSON documents (i.e., text input) and therefore does not use an ObjectInputStream (i.e., binary input).

  • How can we configure Spring to use our LookAheadObjectInputStream instead of ConfigurableObjectInputStream?

The only place where you can change the ObjectInputStream used by the core Spring Framework is in a custom extension of the HttpInvokerServiceExporter that overrides the createObjectInputStream(InputStream) method. Note, however, that Spring's remoting technologies support was deprecated in conjunction with #25379.

#19880 updated the guidelines for serialization-based endpoints, leading to the following note in the reference manual:

Be aware of vulnerabilities due to unsafe Java deserialization: Manipulated input streams can lead to unwanted code execution on the server during the deserialization step. As a consequence, do not expose HTTP invoker endpoints to untrusted clients. Rather, expose them only between your own services. In general, we strongly recommend using any other message format (such as JSON) instead.

If you are concerned about security vulnerabilities due to Java serialization, consider the general-purpose serialization filter mechanism at the core JVM level, originally developed for JDK 9 but backported to JDK 8, 7 and 6 in the meantime. See https://blogs.oracle.com/java-platform-group/entry/incoming_filter_serialization_data_a and https://openjdk.java.net/jeps/290.

In general, Spring cannot influence how third-party libraries handle Java deserialization (i.e., binary input).

If you really need to use Java deserialization to process binary input from untrusted sources, as an alternative to the LookAheadObjectInputStream you have shared, you might be better off registering a custom ObjectInputFilter.

However, we strongly recommend using any other message format (such as JSON) instead.

In light of the above, I am closing this issue.

@sbrannen sbrannen closed this as completed Mar 1, 2021
@sbrannen sbrannen added status: invalid An issue that we don't feel is valid and removed status: waiting-for-triage An issue we've not yet triaged or decided on labels Mar 1, 2021
@mattjerry
Copy link
Author

thank you. I have one question:

When spring and jpa/hibernate are implemented, does hibernate use the ConfigurableObjectInputStream?
Thanks for confirmation here that typically it is NO.

One more point is that as per JPA spec, PKs of classes with composite IDs have to be serializable. And in this specific context , can you pl confirm that hibernate would not be using Spring's ConfigurableObjectInputStream in this case as well? when there are composite IDs?

@sbrannen
Copy link
Member

sbrannen commented Mar 1, 2021

One more point is that as per JPA spec, PKs of classes with composite IDs have to be serializable. And in this specific context , can you pl confirm that hibernate would not be using Spring's ConfigurableObjectInputStream in this case as well? when there are composite IDs?

That was covered by this part of my response:

In general, Spring cannot influence how third-party libraries handle Java deserialization (i.e., binary input).

In any case, when you're using Hibernate/JPA and your entities get serialized/deserialized (for example, due to the use of a 2nd-level cache with overflow to disk), you're talking about classes under your control. In other words, this is trusted code that is undergoing serialization. It's not some potentially malicious binary input provided by an external source.

@mattjerry
Copy link
Author

Thanks a lot for your clarifications. This really helped.

This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
status: invalid An issue that we don't feel is valid
Projects
None yet
Development

No branches or pull requests

3 participants