Search code examples
javasecurityxstream

Malicious object injection with xstream


Can I safely use XStream to process XML coming from outside of my system ? What's the best practice when dealing with "potentially malicious XML" using xstream ?

Let's say, I have a class somewhere in my code like this :

 package hazard;
 class Dangerous {
    public Dangerous() {
       AtomicBomb.getInstance().nuke();
    }
 }

A malicious user, might submit a XML file such as :

 <hazard.Dangerous/>

and make XStream calls the nuke() method.

This example is quite theoretical. As was pointed out, I do not expect constructor to do this kind of things. But can I be certain that no constructor in any lib available in the classpath is free from such issues (for example, allocate some ressource like a file descriptor).

The point is that sending a XML file allows an attacker to create arbitrary objects. A more realistic approach might be using some class instead of another one.

public class Foo<T implements Bar> {
    private T t;
    // Getters/setters ...
}

public interface Bar {
   public void bar();
}

public class Bar1 implements Bar {
   // ...
}

public class Bar2 implements Bar {
   // ...
}

With the (malicious) XML input :

<foo>
  <!-- I expect bar1 -->
  <package.Bar2/>
</foo>

Now with the Java code :

Bar<Foo1> bar = (Bar<Foo1>) xstream.fromXML(xml);
// I expect to have a bar1 but I have a bar2.
bar.getT().foo();

At first glance, the solution is to provide a custom Mapper (the job being done in the realClass() method).


Solution

  • Never ever allow xstream (or any other serialization framework) to marshal anything but clean, pure javabeans (getters and setters).

    UPDATE: Your mentioned theory about using a Mapper should work, although it will require some amount of scaffolding and custom config being built by you. Another way is to use the feature of XStream to specify a dedicated classloader for resolving classes. What you would try is to put all classes that SHOULD be allowed to be marshalled by xstream in a separate JAR (think of it as a domain module). Then create a clean classloader that only loads that JAR and assign it to xstream. That way, xstream will not know of any classes outside of it's scope, failing to deserialize anything you don't want it to.

    Try something like

    ClassLoader bootstrapClassLoader = ClassLoader.getSystemClassLoader().getParent();
    List urls = new ArrayList();
    urls.add(new File("yourJarOfXstreamBeanClasses.jar").toURL());
    ClassLoader xstreamClassLoader = new URLClassLoader(urls.toArray(new URL[0]), bootstrapClassLoader);
    XStream xstream = new XStream();
    xstream.setClassLoader(xstreamClassLoader);