Tag Archives: Java

Safer deserialization in Spring Security OAuth2

The Java standard library provides the ObjectInputStream class which offers a convenient way for deserializing Java objects. Unfortunately, this way is not safe by default. Using this class may open the doors for Java deserialization attacks which in the worse case may result in arbitrary code execution.

I recently discovered that Spring Security OAuth2 library may be vulnerable to such an attack. Fortunately, there is one strong pre-requisite for a successful attack which may be difficult to meet for an adversary. Nevertheless, I thought it might be better to make the library a bit safer, and the project maintainers kindly accepted the contribution. Here are the details.

Safer deserialization in Spring Security OAuth 2.4.0

The issue

Spring Security OAuth2 can store authentication info and user details to a SQL or Redis database. Before storing data to the database, the library serialize it with the default Java serialization mechanism offered by theObjectOutputStream. Then, after reading the data from the database, the library unsafely deserializes it with the ObjectInputStream class. See SerializationUtils class:

public static  T deserialize(byte[] byteArray) {
         ObjectInputStream oip = null;
         try {
             oip = new ConfigurableObjectInputStream(
                     new ByteArrayInputStream(byteArray),
                     Thread.currentThread().getContextClassLoader());
             @SuppressWarnings("unchecked")
             T result = (T) oip.readObject();

The ConfigurableObjectInputStream class, which is provided by the Spring Framework, just wraps the InputObjectStream class without adding any security check.

It means that if an attacker is able to put malicious data into the database, then he can in the worse case execute arbitrary code, and as a result, compromise the whole application. However, there are a couple of requirements for a successful exploit.

First, the attacker has to build a deserialization gadget using classes that are available in the application’s JVM. Most probably it should not be a big problem since the Java standard library provides many dangerous classes. Plus, an application can load many libraries which may also help to build a deserialization gadget.

Second, to take advantage of this deserialization flaw, the attacker has to find a way how he can put malicious data into the database. For example, he can try to find an SQL injection. However, it may be not that easy, so that this requirement may be difficult to meet.

I found the problem by reviewing the code. Then, I reported it to the Pivotal Security Team. But they decided not to consider it as a vulnerability in the library because of the second requirement above. However, they welcomed a patch that adds a defense-in-depth measure to prevent such deserialization attacks.

The solution

To prevent Java deserialization vulnerabilities, an application has to restrict a set of classes which may be deserialized. One of the best ways is implementing a whitelist of allowed classes. There are three ways of how such a protection mechanism can be implemented:

  1. Use the filtering API introduced in JEP 290.
  2. Use the ValidatingObjectInputStream class from Apache Commons IO.
  3. Override the ObjectInputStream.resolveClass() method, and implement the whitelisting there.

The first way would require an application to use the Java versions which have JEP 290. The second way would add an additional dependency to Spring Security OAuth. I decided to follow the third way since it doesn’t introduce any additional dependency:

  • Added a new SaferObjectInputStream class which checks if classes are allowed for deserialization.
  • Defined a whitelist of classes as java.lang.*, java.util.* and org.springframework.security.*.
  • Updated the RedisTokenStore class to use the SaferObjectInputStream with the whitelist.
  • Updated the JDBC classes to use the SaferObjectInputStream with the whitelist.

The update was released in Spring Security OAuth2 2.3.7 but unfortunately, the solution caused a problem. It turned out that the whitelist is too strict. If an application stores custom implementations of tokens or user details, then the new version of the library fails to deserialize them due to the restrictive whitelist. Furthermore, there was no way how a user could modify the whitelist to make the application work again. The issue was reported by several users.

I fixed the problem in 2.4.0 by introducing a new API which allows a user to specify a custom whitelist. The default whitelist still contains java.lang.*, java.util.* and org.springframework.security.* classes. At first, I updated the library to apply the whitelist by default. But then, the project maintainer asked me to make it an opt-in option. The reason was that 2.4.0 is a minor release, so that it should not introduce any problem for an application when it migrates to the new version.

Here is what I did to make deserialization great again:

  1. Added a new SerializationStrategy interface with two implementations: DefaultSerializationStrategy and WhitelistedSerializationStrategy.
  2. The DefaultSerializationStrategy uses unsafe deserialization.
  3. The WhitelistedSerializationStrategy allows specifying a whitelist of classes which are allowed for deserialization. If no classes specified, the strategy uses the default whitelist: java.lang.*, java.util.* and org.springframework.security.*.
  4. Added a new static SerializationStrategy field to the SerializationUtils class. The default strategy is unsafe DefaultSerializationStrategy.
  5. The strategy can be overridden by calling a new SerializationUtils.setSerializationStrategy() method, or by specifying the strategy in the META-INF/spring.factories file.

Now a user can enable the default whitelist with the following code:

SerializationUtils.setSerializationStrategy(new WhitelistedSerializationStrategy());

Or, the user can implement his own serialization strategy, for example, by extending the WhitelistedSerializationStrategy class:

package org.custom.impl.oauth2;

public class CustomSerializationStrategy
    extends WhitelistedSerializationStrategy {

        private static final List<String> ALLOWED_CLASSES 
                = new ArrayList<String>();
        static {
            ALLOWED_CLASSES.add("java.lang.");
            ALLOWED_CLASSES.add("java.util.");
            ALLOWED_CLASSES.add("org.springframework.security.");
            ALLOWED_CLASSES.add("org.custom.impl.oauth2.");
        }

        CustomSerializationStrategy() {
            super(ALLOWED_CLASSES);
        }
    }
}

And here is how the user can specify the WhitelistedSerializationStrategy strategy in META-INF/spring.factories file:

org.springframework.security.oauth2.common.util.SerializationStrategy = \
org.springframework.security.oauth2.common.util.WhitelistedSerializationStrategy

Of course, META-INF/spring.factories allows using a custom serialization strategy as well.

Conclusion

By default, Spring Security OAuth2 library still uses deserialization in an unsafe way which may make an application vulnerable. Although the discussed deserialization flaw may be difficult to exploit, it may be better to enable the WhitelistedSerializationStrategy to be on the safe side.

References

  1. Spring Security OAuth
  2. ObjectInputStream
  3. JEP 290
  4. ValidatingObjectInputStream

CVE-2019-12415: XML processing vulnerability in Apache POI

Apache POI is a popular Java library for working with Microsoft documents. For example, it allows you reading and writing Microsoft Excel files using Java. When I was recently looking into the library, I noticed a little vulnerability which then became CVE-2019-12415. The issue has been fixed in POI 4.1.1. Below are the details.

CVE-2019-12415: XML processing vulnerability in Apache POI
Continue reading

Safer deserialization with new Jackson 2.10

New Jackson 2.10 was released on Sep 26th, 2019. Everyone who uses the library and also scans their applications for known vulnerabilities knows about the problem with endless CVEs that have been reporting against Jackson. Let’s try to understand what makes an application vulnerable and how the new version of Jackson can help to prevent deserialization vulnerabilities.

Safer deserialization with new Jackson 2.10
Continue reading

TLS enhancements in Java 13

Java 13 was released on Sep 13th, 2019. Although the new Java doesn’t contain major updates in security libraries, nevertheless it has several notable updates in the TLS implementation. Let’s take a closer look at how Java 13 helps to make your TLS connections faster and more secure.

TLS enhancements in Java 13
Continue reading

What’s new in Java 13

Java 13 is going to be released on Sep 17th, 2019. Besides ~2300 bug fixes and small enhancements, the new version of Java contains 5 major enhancements which are also called JEPs (Java Enhancement Proposals). Let’s take a closer look at these major updates: text blocks, switch expressions, re-implemented the legacy Socket API, updates to ZGC and dynamic CDS archives.

What is new in Java 13
Continue reading

What’s new in Java 12

Let’s take a look what is inside Java 12. The new Java release contains less major enhancements than the previous version: 8 JEPs in Java 12 vs 17 JEPs in Java 11. As you of course remember, JEP stands for JDK Enhancement Proposal. Java 11 also had more closed entries in Jira: ~2700 in Java 11 vs ~2400 in Java 12. But it’s only mid of Feb 2019, maybe they can deliver 300 Jira entries by Mar 19th 2019 when Java 12 is planned to be released. Now let’s take a closed look what is in Java 12.

Continue reading

Configuring security for REST API in Spring

In most cases, REST APIs should be accessed only by authorized parties. Spring framework provides many ways to configure authentication and authorization for an application. Another good thing is that the framework usually provides relatively good default settings. But nevertheless, it may be better to understand what’s going on rather then rely on the defaults.

This post contains a list of things which may be good to pay attention to when you configure or review authentication and authorization settings for a RESTful application based on Spring (boot) framework. However this is not a comprehensive guideline (if such a guideline even exist) which tells how to configure authentication and authorization for an application based on Spring framework. It’s more like a collection of tips and suggestions. Furthermore, any other suggestions and comments are more than welcome.

Continue reading

What’s new security features in Java 11?

Java 11 was released on Sep 25th, 2018. This is the first long-term support release produced under the six-month cadence release model. Besides a huge number of small improvements and bug fixes, the new release contains 17 major enhancements including:

  • several updates in the Hotspot and garbage collectors
  • new HTTP client
  • Unicode 10
  • deprecating Nashorn JavaScript Engine and Pack200 tool
  • removing the Java EE and CORBA Modules
  • local-variable syntax for Lambda parameters
  • launch single-file source-code programs
  • and finally several security features

Although all these features are pretty cool, let’s focus on security in this post.

Continue reading

Integrating OWASP Dependency Check in to development process

OWASP Dependency Check is a well known open-source tool which can track dependencies in your project and identify components with known published vulnerabilities. The tool supports multiple languages and platforms such as Java, .NET, Ruby and Python. One of the simplest ways how you can use Dependency Check in your project is just to run it manually. This way has at least one disadvantage: you have to make sure that you run the tool regularly. Fortunately there is a couple of ways how you can automate this process.

But unfortunately sometimes it’s not enough just to automate something. If the tool reports a vulnerability it means someone has to fix it. At least it would be good to evaluate the problem. In a perfect world, all issues are addressed immediately, but in the real world, development teams always have no time for that. Besides integrating Dependency Check to CI/CD, there may be a couple of other steps to get vulnerable dependencies updated.

Continue reading