diff --git a/pippo-content-type-parent/pippo-xstream/pom.xml b/pippo-content-type-parent/pippo-xstream/pom.xml index 0f3c4d303..a42363993 100644 --- a/pippo-content-type-parent/pippo-xstream/pom.xml +++ b/pippo-content-type-parent/pippo-xstream/pom.xml @@ -15,7 +15,7 @@ XStream integration - 1.4.9 + 1.4.11.1 diff --git a/pippo-content-type-parent/pippo-xstream/src/main/java/ro/pippo/xstream/XstreamEngine.java b/pippo-content-type-parent/pippo-xstream/src/main/java/ro/pippo/xstream/XstreamEngine.java index f4e6788a5..2922c1209 100644 --- a/pippo-content-type-parent/pippo-xstream/src/main/java/ro/pippo/xstream/XstreamEngine.java +++ b/pippo-content-type-parent/pippo-xstream/src/main/java/ro/pippo/xstream/XstreamEngine.java @@ -21,6 +21,9 @@ import ro.pippo.core.HttpConstants; import com.thoughtworks.xstream.XStream; +import ro.pippo.core.util.WhitelistObjectInputStream; + +import java.util.regex.Pattern; /** * An XmlEngine based on XStream. @@ -45,6 +48,10 @@ private XStream xstream() { xstream.autodetectAnnotations(true); // prevent xstream from creating complex XML graphs xstream.setMode(XStream.NO_REFERENCES); + + //setup security + xstream.allowTypes((String[]) WhitelistObjectInputStream.getWhitelistedClassNames().toArray()); + xstream.allowTypesByRegExp((Pattern[]) WhitelistObjectInputStream.getWhitelistedRegExp().toArray()); return xstream; } diff --git a/pippo-core/src/main/java/ro/pippo/core/util/WhitelistObjectInputStream.java b/pippo-core/src/main/java/ro/pippo/core/util/WhitelistObjectInputStream.java index 6b05ef6dc..8d3ae6f00 100644 --- a/pippo-core/src/main/java/ro/pippo/core/util/WhitelistObjectInputStream.java +++ b/pippo-core/src/main/java/ro/pippo/core/util/WhitelistObjectInputStream.java @@ -24,6 +24,7 @@ import java.io.ObjectStreamClass; import java.util.ArrayList; import java.util.List; +import java.util.regex.Pattern; /** * When deserializing objects, first check that the class being deserialized is in the allowed whitelist. @@ -33,6 +34,7 @@ public class WhitelistObjectInputStream extends ObjectInputStream { private static List whiteClassNames; + private static List whiteRegExp; static { loadWhitelist(WhitelistObjectInputStream.class.getResourceAsStream(PippoConstants.LOCATION_OF_PIPPO_WHITELIST_SERIALIZATION)); @@ -44,7 +46,7 @@ public WhitelistObjectInputStream(InputStream in) throws IOException { protected Class resolveClass(ObjectStreamClass descriptor) throws ClassNotFoundException, IOException { String className = descriptor.getName(); - if (!isWhiteListed(className)) { + if ((!isWhiteListed(className)) && (!isWhiteListedRegex(className))) { throw new InvalidClassException("Unauthorized deserialization attempt", className); } @@ -61,6 +63,16 @@ private boolean isWhiteListed(String className) { return false; } + private boolean isWhiteListedRegex(String className) { + for (Pattern pattern : whiteRegExp) { + if (pattern.matcher(className).matches()) { + return true; + } + } + + return false; + } + /** * Load the whitelist from an {@link InputStream}. * The content of the {@code InputStream} is in format: @@ -68,6 +80,8 @@ private boolean isWhiteListed(String className) { * # Java * java.util.ArrayList * java.util.HashMap + * A regular expression whitelisting the whole java.lang package and its sub-packages. + * /java.lang.* / * * # Pippo * ro.pippo.session.DefaultSessionData @@ -75,6 +89,7 @@ private boolean isWhiteListed(String className) { * } * * A line that starts with {@code #} is a comment and will be ignored. + * A line that starts and ends with {@code /} is interpreted as a regular expression. */ private static void loadWhitelist(InputStream input) { String content; @@ -91,6 +106,8 @@ private static void loadWhitelist(InputStream input) { if (line.startsWith("#")) { // it's a comment; ignore line continue; + } else if (line.startsWith("/") && (line.endsWith("/"))) { + addWhiteRegExp(Pattern.compile(line.substring(1, line.length() - 2))); } addWhiteClassName(line); @@ -101,4 +118,24 @@ private static void addWhiteClassName(String className) { whiteClassNames.add(className); } + private static void addWhiteRegExp(Pattern pattern) { + whiteRegExp.add(pattern); + } + + /** + * Returns the whitelisted class names. + * @return the whitelisted class names. + */ + public static List getWhitelistedClassNames() { + return whiteClassNames; + } + + /** + * Returns the whitelisted regular expressions. + * @return the whitelisted regular expressions. + */ + public static List getWhitelistedRegExp() { + return whiteRegExp; + } + }