== Why is this an issue?

Deserialization takes a stream of bits and turns it into an object. If the stream contains the type of object you expect, all is well. But if you're deserializing untrusted input, and an attacker has inserted some other type of object, you're in trouble. Why? There are a few different attack scenarios, but one widely-documented one goes like this: Deserialization first instantiates an ``++Object++``, then uses the  ``++readObject++`` method to populate it. If the attacker has overridden ``++readObject++`` then he is entirely in control of what code executes during that process. It is only after ``++readObject++`` has completed that your newly-minted ``++Object++`` can be cast to the type you expected. A ``++ClassCastException++`` or ``++ClassNotFoundException++`` will be thrown, but at that point it's too late.


To prevent this, you should either use look-ahead deserialization (pre-Java 9) or filtering to make sure you're dealing with the correct type of object _before_ you act on it.


Several third-party libraries offer look-ahead deserialization, including:

* ikkisoft's ``++SerialKiller++``
* Apache Commons Class IO's ``++ValidatingObjectInputStream++``
* contrast-rO0's ``++SafeObjectInputStream++``

Note that it is possible to set a deserialization filter at the level of the JVM, but relying on that requires that your environment be configured perfectly. Every time. Additionally, such a filter may have unwanted impacts on other applications in the environment. On the other hand, setting a filter as close as possible to the deserialization that uses it allows you to specify a very narrow, focused filter.


=== Noncompliant code example

[source,java]
----
FileInputStream in = new FileInputStream("obj");
ObjectInputStream ois = new ObjectInputStream(in);  // Noncompliant
Foo reconstitutedFoo = (foo)ois.readObject();
----


=== Compliant solution

[source,java]
----
FileInputStream in = new FileInputStream("obj");
ObjectInputStream ois = new SerialKiller(is, "/etc/serialkiller.conf");
String msg = (String) ois.readObject();
----
Or for Java 9

[source,java]
----
class MyFilter implements ObjectInputFilter {
  @Override
  public Status checkInput(Filterinfo filterInfo) { ...}
}

//...
    FileInputStream in = new FileInputStream("obj");
    ObjectInputStream ois = new ObjectInputStream(in);
    ois.setObjectInputFilter(new MyFilter());  //
    Foo reconstitutedFoo = (foo)ois.readObject();
----


== Resources

* CERT - https://wiki.sei.cmu.edu/confluence/display/java/SER12-J.+Prevent+deserialization+of+untrusted+data[SER12-J. Prevent deserialization of untrusted data]
* OWASP - https://owasp.org/Top10/A08_2021-Software_and_Data_Integrity_Failures/[Top 10 2021 Category A8 - Software and Data Integrity Failures]
* OWASP - https://owasp.org/www-project-top-ten/2017/A8_2017-Insecure_Deserialization[Top 10 2017 Category A8 - Insecure Deserialization]


ifdef::env-github,rspecator-view[]
'''
== Comments And Links
(visible only on this page)

=== duplicates: S4508

endif::env-github,rspecator-view[]
