Codebase list libxstream-java / debian/1.4.8-1 xstream-distribution / src / content / security.html
debian/1.4.8-1

Tree @debian/1.4.8-1 (Download .tar.gz)

security.html @debian/1.4.8-1raw · history · blame

<html>
<!--
 Copyright (C) 2014 XStream committers.
 All rights reserved.
 
 The software in this package is published under the terms of the BSD
 style license a copy of which has been included with this distribution in
 the LICENSE.txt file.
 
 Created on 09. January 2014 by Joerg Schaible
 -->
  <head>
    <title>Security Aspects</title>
  </head>

  <body>
	<p>XStream is designed to be an easy to use library.  It takes its main task seriously: converting Java objects to
	XML, and XML to Java objects. As a result, it is possible to create an instance of XStream with the default
	constructor, call a method to convert an object into XML, then call another method to turn the XML back into an
	equivalent Java object.  By design, there are few limits to the type of objects XStream can handle.</p>
 
	<p>This flexibility comes at a price. XStream applies various techniques under the hood to ensure it is able to
 	handle all types of objects.  This includes using undocumented Java features and reflection.  The XML generated by
 	XStream includes all information required to build objects of almost any type.  This introduces a potential
 	security problem.</p>
 
	<p>The XML provided to XStream for conversion to a Java object can be manipulated to inject objects into the
 	unmarshalled object graph, which were not present at marshalling time. An attacker could exploit this to execute
 	arbitrary code or shell commands in the context of the server running the XStream process.  This issue is
 	identified by CVE-2013-7285.</p>
 
	<p>Note that the XML data could be manipulated on different levels. For example, manipulating values on existing
 	objects (such as a price value), or breaking the format and causing the XML parser to fail.  The latter case will
 	raise an exception, but the former case must be handled by validity checks in any application which processes
 	user-supplied XML.  The worst case scenario is injection of arbitrary code or shell commands, as noted above.</p>
     
    <h2 id="external">External Security</h2>

	<p>An active Java Security Manager can prevent actions required by XStream components or converters.  The same
	applies to environments such as Google Application Engine.  XStream tries to some extent to check the functionality
	of a converter before it claims to handle a type.</p>
         
	<p>Therefore it is possible that XStream behaves differently in such an environment, because a converter suddenly
 	no longer handles a special type or any type at all.  It is essential that an application that will have to run in
 	such an environment is tested at an early stage to prevent nasty surprises.</p>
      
    <h2 id="implicit">Implicit Security</h2>
	
	<p>As explained above, it is possible to inject other object instances if an attacker is able to define the data
	used to deserialize the Java objects (typically XML, but XStream supports other formats like JSON).  A known
	exploit can be created with the help of the Java runtime library using the Java Bean
	<a href="http://docs.oracle.com/javase/7/docs/api/java/beans/EventHandler.html">EventHandler</a>.  As an instance
	for the <a href="http://docs.oracle.com/javase/7/docs/api/java/lang/reflect/InvocationHandler.html">InvocationHandler</a>
	of a dynamic proxy, it can be used to install a redirect for an arbitrary call to the original object to the method
	of a completely different instance of an embedded object of the EventHandler itself.</p>
         
	<p>This scenario can be used perfectly to replace/inject a dynamic proxy with such an EventHandler at any location
	in the XML where its parent expects an object of such an interface's type or a simple object instance (any list
	element will suffice).  The usage of a ProcessBuilder as an embedded element, coupled with the redirection of any
	call to the ProcessBuilder's <a href="http://docs.oracle.com/javase/7/docs/api/java/lang/ProcessBuilder.html#start()">start()</a>
	method allows an attacker to call shell commands.  Knowing how to define such an attack is the only prerequisite.</p>
         
	<p>Starting with XStream 1.4.7, an instance of the EventHandler is no longer handled by default.  You have to
 	explicitly register a ReflectionConverter for the EventHandler type, if your application has the requirement to
 	persist such an object.  However, you still have to take special care regarding the location of the persisted data,
 	and how your application can ensure its integrity.</p>
         
	<p class=highlight>Note: this vulnerability is not even a special problem of XStream.  XML being deserialized by
 	XStream acts here like a script, and the scenario above can be created with any script that is executed within a
 	Java runtime (e.g. using its JavaScript interpreter) if someone is able to manipulate it externally.  The key
 	message for application developers is that deserializing arbitrary user-supplied content is a dangerous proposition
 	in all cases.</p>
    
    <h2 id="explicit">Explicit Security</h2>
    
	<p>While XStream implicitly avoids the vulnerability scenario with the EventHandler class, there might be other
	combinations with types from well-known and commonly-used Java libraries such as ASM, CGLIB, Groovy, or even in
	the Java runtime, that are currently simply unknown.</p>
     
	<p>Starting with XStream 1.4.7, it is possible to define <a href="#framework">permissions</a> for types, to check
	the type of an object that should be unmarshalled. Those permissions can be used to allow or deny types explicitly.
	With these permissions it is at least not possible to inject unexpected types into an object graph. Any application
	that deserializes data from an external source should at least use this feature to limit the danger of arbitrary
	command execution.</p>
         
	<p class=highlight>Apart from value manipulations, this implementation still allows the injection of allowed
	objects at wrong locations, e.g. inserting an integer into a list of strings.</p>
         
	<p>Separate to the XStream security framework, it has always been possible to overwrite the setupConverter method
	of XStream to register only the required converters.</p>
    
    <h2 id="validation">XML Validation</h2>

	<p>XML itself supports input validation using a schema and a validating parser.  With XStream, you can use e.g. a
	StAX parser for validation, but it will take some effort to ensure that the XML read and written by XStream matches
	the schema in first place. Typically you will have to write some custom converters, but it can be worth the effort
	depending on the use case.</p>

    <h1 id="framework">Security Framework</h1>

	<p>Noted above, it might be possible that other combinations are found with the Java runtime itself, or other
	commonly-used Java libraries that allow a similar vulnerability like the known case using the Java Beans
	EventHandler.  To prevent such a possibility at all, XStream version 1.4.7 and above contains a security framework,
	allowing application developers to define which types are allowed to be unmarshalled with XStream.</p>
         
	<p>The core interface is <a href="javadoc/com/thoughtworks/xstream/security/TypePermission.html">TypePermission</a>.
	The <a href="javadoc/com/thoughtworks/xstream/mapper/SecurityMapper.html">SecurityMapper</a> will evaluate a list
	of registered instances for every type that will be required while unmarshalling input data.  The interface has one
	simple method:</p><div class="Source Java"><pre>boolean allow(Class&lt;?&gt;);</pre></div>
         
	<p>The <a href="javadoc/com/thoughtworks/xstream/XStream.html">XStream</a> facade provides the following methods to
	register such type permissions within the SecurityMapper:</p><div class="Source Java">
<pre>XStream.addPermission(TypePermission);
XStream.allowTypes(Class[]);
XStream.allowTypes(String[]);
XStream.allowTypesByRegExp(String[]);
XStream.allowTypesByRegExp(Pattern[]);
XStream.allowTypesByWildcard(String[]);
XStream.allowTypeHierary(Class);
XStream.denyPermission(TypePermission);
XStream.denyTypes(Class[]);
XStream.denyTypes(String[]);
XStream.denyTypesByRegExp(String[]);
XStream.denyTypesByRegExp(Pattern[]);
XStream.denyTypesByWildcard(String[]);
XStream.denyTypeHierary(Class);</pre></div>

	<p>The sequence of registration is essential. The most recently registered permission will be evaluated first.</p>
         
	<p>Every TypePermission has three options to implement the allow method and make decisions on the provided type:<p>
	<ul>
	<li>if the method returns <i>true</i>, the type is accepted and no other permissions are evaluated</li>
	<li>if the method returns <i>false</i>, the implementation cannot judge over the type and the SecurityMapper will
	continue with the next permission instance in its registration list</li>
	<li>the method throws a <a href="javadoc/com/thoughtworks/xstream/security/ForbiddenClassException.html">ForbiddenClassException</a>
	to stop the unmarshalling process</li>
	</ul>
         
    <h2 id="predefined">Predefined Permission Types</h2>

	<p>XStream provides some TypePermission implementations to allow any or no type at all, to allow primitive types
	and their counterpart, null, array types, implementations match the name of the type by regular or wildcard
	expression and one to invert a permission.</p>
	
	<table class="examplesTable" summary="Overview over all type permissions delivered with XStream">
	<!-- .................................................................................................. -->
	<tr>
	    <th>Permission</th>
	    <th>Description</th>
	    <th>Example</th>
	    <th>Default</th>
	</tr>
	<tr>
	    <td><a href="javadoc/com/thoughtworks/xstream/security/AnyTypePermission.html">AnyTypePermission</a></td>
	    <td>Allow any type.  You may use the ANY instance directly. A registration of this permission will wipe any
	    prior one.</td>
	    <td>&nbsp;</td>
	    <td>yes</td>
	</tr>
	<tr>
	    <td><a href="javadoc/com/thoughtworks/xstream/security/ArrayTypePermission.html">ArrayTypePermission</a></td>
	    <td>Allow any array type.  You may use the ARRAYS instance directly.</td>
	    <td>&nbsp;</td>
	    <td>no</td>
	</tr>
	<tr>
	    <td><a href="javadoc/com/thoughtworks/xstream/security/CGLIBProxyTypePermission.html">CGLIBProxyTypePermission</a></td>
	    <td>Allow any CGLIB proxy type.  You may use the PROXIES instance directly.</td>
	    <td>&nbsp;</td>
	    <td>no</td>
	</tr>
	<tr>
	    <td><a href="javadoc/com/thoughtworks/xstream/security/ExplicitTypePermission.html">ExplicitTypePermission</a></td>
	    <td>Allow types explicitly by name.</td>
	    <td>&nbsp;</td>
	    <td>&ndash;</td>
	</tr>
	<tr>
	    <td><a href="javadoc/com/thoughtworks/xstream/security/InterfaceTypePermission.html">InterfaceTypePermission</a></td>
	    <td>Allow any interface type.  You may use the INTERFACES instance directly.</td>
	    <td>&nbsp;</td>
	    <td>no</td>
	</tr>
	<tr>
	    <td><a href="javadoc/com/thoughtworks/xstream/security/NoPermission.html">NoPermission</a></td>
	    <td>Invert any other permission.  Instances of this type are used by XStream in the deny methods.</td>
	    <td>&nbsp;</td>
	    <td>no</td>
	</tr>
	<tr>
	    <td><a href="javadoc/com/thoughtworks/xstream/security/NoTypePermission.html">NoTypePermission</a></td>
	    <td>Allow no type.  You may use the NONE instance directly. A registration of this permission will wipe any
	    prior one.</td>
	    <td>&nbsp;</td>
	    <td>&ndash;</td>
	</tr>
	<tr>
	    <td><a href="javadoc/com/thoughtworks/xstream/security/NullPermission.html">NullPermission</a></td>
	    <td>Allow null as type.  You may use the NULL instance directly.</td>
	    <td>&nbsp;</td>
	    <td>no</td>
	</tr>
	<tr>
	    <td><a href="javadoc/com/thoughtworks/xstream/security/PrimitiveTypePermission.html">PrimitiveTypePermission</a></td>
	    <td>Allow any primitive type and its boxed counterpart (incl void).  You may use the PROXIES instance directly.</td>
	    <td>&nbsp;</td>
	    <td>no</td>
	</tr>
	<tr>
	    <td><a href="javadoc/com/thoughtworks/xstream/security/ProxyTypePermission.html">ProxyTypePermission</a></td>
	    <td>Allow any Java proxy type.  You may use the PROXIES instance directly.</td>
	    <td>&nbsp;</td>
	    <td>no</td>
	</tr>
	<tr>
	    <td><a href="javadoc/com/thoughtworks/xstream/security/RegExpTypePermission.html">RegExpTypePermission</a></td>
	    <td>Allow any type that matches with its name a regular expression.</td>
	    <td class="example">.*\\.core\\..*<br/>[^$]+</td>
	    <td>&ndash;</td>
	</tr>
	<tr>
	    <td><a href="javadoc/com/thoughtworks/xstream/security/TypeHierarchyPermission.html">TypeHierarchyPermission</a></td>
	    <td>Allow types of a hierarchy.</td>
	    <td>&nbsp;</td>
	    <td>&ndash;</td>
	</tr>
	<tr>
	    <td><a href="javadoc/com/thoughtworks/xstream/security/WildcardTypePermission.html">WildcardTypePermission</a></td>
	    <td>Allow any type that matches with its name a wildcard expression.</td>
	    <td class="example">java.lang.*<br/>java.util.**</td>
	    <td>&ndash;</td>
	</tr>
    </table>

    <h2 id="example">Example Code</h2>

	<p>XStream uses the AnyTypePermission by default, i.e. any type is accepted.  You have to clear out this default
	and register your own permissions to activate the security framework (the Blog type is from the
	<a href="alias-tutorial.html">Alias Tutorial</a>):</p>
<div class="Source Java"><pre>XStream xstream = new XStream();
// clear out existing permissions and set own ones
xstream.addPermission(NoPermissionType.NONE);
// allow some basics
xstream.addPermission(NullPermission.NULL);
xstream.addPermission(PrimitiveTypePermission.PRIMITIVES);
xstream.allowTypeHierarchy(Collection.class);
// allow any type from the same package
xstream.allowTypesByWildcard(new String[] {
    Blog.class.getPackage().getName()+".*"
});
</pre></div>

  <p>You may have a further look at XStream's acceptance tests, the security framework is enabled there in general.</p>
  </body>
 </html>