From a45db285f0bb0b232d97ba5ab63ac9c95319d683 Mon Sep 17 00:00:00 2001 From: Lei Zhiyuan Date: Fri, 13 Jul 2018 18:16:19 +0800 Subject: [PATCH] Fix serialization security vulnerabilities. (#8) * Fix CI build error on JDK 1.6 which cause by TLS upgrade of the server. * Upgrade version to v3.3.1 * Fix serialization security vulnerabilities. --- .travis.yml | 3 +- pom.xml | 2 +- .../internal/InternalNameBlackListFilter.java | 91 +++++++----- .../com/caucho/hessian/io/Hessian2Input.java | 14 ++ .../com/caucho/hessian/io/HessianInput.java | 27 ++++ .../alipay/hessian/ClassNameResolverTest.java | 2 +- .../InternalNameBlackListFilterTest.java | 2 +- .../hessian/test/SimpleDataGenerator.java | 4 +- .../{TestCons.java => SimpleTestCons.java} | 16 +- tools/ci/.travis.settings.xml | 138 ++++++++++++++++++ 10 files changed, 246 insertions(+), 53 deletions(-) rename src/test/java/com/caucho/hessian/test/{TestCons.java => SimpleTestCons.java} (82%) create mode 100644 tools/ci/.travis.settings.xml diff --git a/.travis.yml b/.travis.yml index 13ec18f..e52185d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,7 +16,8 @@ before_install: && wget https://archive.apache.org/dist/maven/maven-3/3.2.5/binaries/apache-maven-3.2.5-bin.zip && unzip -qq apache-maven-3.2.5-bin.zip && export M2_HOME=$PWD/apache-maven-3.2.5 - && export PATH=$M2_HOME/bin:$PATH + && export PATH=$M2_HOME/bin:$PATH + && cp ./tools/ci/.travis.settings.xml $HOME/.m2/settings.xml && mvn -version install: diff --git a/pom.xml b/pom.xml index 9ce54bf..e65ce07 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.alipay.sofa hessian - 3.3.0 + 3.3.1 jar ${project.groupId}:${project.artifactId} diff --git a/src/main/java/com/alipay/hessian/internal/InternalNameBlackListFilter.java b/src/main/java/com/alipay/hessian/internal/InternalNameBlackListFilter.java index 5426df2..73b7385 100644 --- a/src/main/java/com/alipay/hessian/internal/InternalNameBlackListFilter.java +++ b/src/main/java/com/alipay/hessian/internal/InternalNameBlackListFilter.java @@ -30,45 +30,58 @@ public class InternalNameBlackListFilter extends NameBlackListFilter { private static final List INTERNAL_BLACK_LIST = Arrays .asList( - "bsh", - "com.mchange", - "com.sun.", - "java.lang.Thread", - "java.net.Socket", - "java.rmi", - "javax.xml", - "org.apache.bcel", - "org.apache.commons.beanutils", - "org.apache.commons.collections.Transformer", - "org.apache.commons.collections.functors", - "org.apache.commons.collections4.comparators", - "org.apache.commons.fileupload", - "org.apache.myfaces.context.servlet", - "org.apache.tomcat", - "org.apache.wicket.util", - "org.codehaus.groovy.runtime", - "org.hibernate", - "org.jboss", - "org.mozilla.javascript", - "org.python.core", - "org.springframework", - "javax.imageio.", - "jdk.nashorn.internal.objects.NativeString", - "org.apache.commons.collections4.functors.InvokerTransformer", - "org.apache.commons.collections4.functors.ChainedTransformer", - "org.apache.commons.collections4.functors.ConstantTransformer", - "org.apache.commons.collections4.functors.InstantiateTransformer", - "org.apache.myfaces.el.CompositeELResolver", - "org.apache.myfaces.el.unified.FacesELContext", - "org.apache.myfaces.view.facelets.el.ValueExpressionMethodExpression", - "java.util.PriorityQueue", - "java.lang.reflect.Proxy", - "javax.management.MBeanServerInvocationHandler", - "javax.management.openmbean.CompositeDataInvocationHandler", - "java.beans.EventHandler", - "java.util.Comparator", - "org.reflections.Reflections", - "net.sf.json.JSONObject"); + "clojure.core$constantly", + "clojure.main$eval_opt", + "com.alibaba.citrus.springext.support.parser.AbstractNamedProxyBeanDefinitionParser$ProxyTargetFactory", + "com.alibaba.citrus.springext.support.parser.AbstractNamedProxyBeanDefinitionParser$ProxyTargetFactoryImpl", + "com.alibaba.citrus.springext.util.SpringExtUtil.AbstractProxy", + "com.alipay.custrelation.service.model.redress.Pair", + "com.caucho.hessian.test.TestCons", + "com.mchange.v2.c3p0.JndiRefForwardingDataSource", + "com.mchange.v2.c3p0.WrapperConnectionPoolDataSource", + "com.rometools.rome.feed.impl.EqualsBean", + "com.rometools.rome.feed.impl.ToStringBean", + "com.sun.jndi.rmi.registry.BindingEnumeration", + "com.sun.jndi.toolkit.dir.LazySearchEnumerationImpl", + "com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl", + "com.sun.rowset.JdbcRowSetImpl", + "com.sun.xml.internal.bind.v2.runtime.unmarshaller.Base64Data", + "java.rmi.server.UnicastRemoteObject", + "java.security.SignedObject", + "java.util.ServiceLoader$LazyIterator", + "javax.imageio.ImageIO$ContainsFilter", + "javax.imageio.spi.ServiceRegistry", + "javax.management.BadAttributeValueExpException", + "javax.naming.InitialContext", + "javax.naming.spi.ObjectFactory", + "javax.script.ScriptEngineManager", + "javax.sound.sampled.AudioFormat$Encoding", + "org.apache.carbondata.core.scan.expression.ExpressionResult", + "org.apache.commons.dbcp.datasources.SharedPoolDataSource", + "org.apache.ibatis.executor.loader.AbstractSerialStateHolder", + "org.apache.ibatis.executor.loader.CglibSerialStateHolder", + "org.apache.ibatis.executor.loader.JavassistSerialStateHolder", + "org.apache.ibatis.executor.loader.cglib.CglibProxyFactory", + "org.apache.ibatis.executor.loader.javassist.JavassistSerialStateHolder", + "org.apache.tomcat.dbcp.dbcp.datasources.SharedPoolDataSource", + "org.apache.wicket.util.upload.DiskFileItem", + "org.apache.xalan.xsltc.trax.TemplatesImpl", + "org.apache.xbean.naming.context.ContextUtil$ReadOnlyBinding", + "org.apache.xpath.XPathContext", + "org.eclipse.jetty.util.log.LoggerLog", + "org.geotools.filter.ConstantExpression", + "org.springframework.aop.aspectj.autoproxy.AspectJAwareAdvisorAutoProxyCreator$PartiallyComparableAdvisorHolder", + "org.springframework.aop.support.DefaultBeanFactoryPointcutAdvisor", + "org.springframework.beans.factory.BeanFactory", + "org.springframework.beans.factory.config.PropertyPathFactoryBean", + "org.springframework.beans.factory.support.DefaultListableBeanFactory", + "org.springframework.jndi.support.SimpleJndiBeanFactory", + "org.springframework.orm.jpa.AbstractEntityManagerFactoryBean", + "org.springframework.transaction.jta.JtaTransactionManager", + "org.yaml.snakeyaml.tokens.DirectiveToken", + "sun.rmi.server.UnicastRef", + "javax.management.ImmutableDescriptor", + "org.springframework.jndi.JndiObjectTargetSource"); /** * 构造函数 diff --git a/src/main/java/com/caucho/hessian/io/Hessian2Input.java b/src/main/java/com/caucho/hessian/io/Hessian2Input.java index 1c74de4..0ce8e64 100644 --- a/src/main/java/com/caucho/hessian/io/Hessian2Input.java +++ b/src/main/java/com/caucho/hessian/io/Hessian2Input.java @@ -2200,6 +2200,12 @@ public Object readObject(Class cl) if (cl == null || cl == Object.class) return readObject(); + // add by zhiyuan @2018-7-10 if in blacklist will throw exception + ClassNameResolver resolver = findSerializerFactory().getClassNameResolver(); + if (resolver != null) { + resolver.resolve(cl.getCanonicalName()); + } + int tag = _offset < _length ? (_buffer[_offset++] & 0xff) : read(); switch (tag) { @@ -2208,6 +2214,9 @@ public Object readObject(Class cl) case 'M': { String type = readType(); + if (resolver != null) { + type = resolver.resolve(type); + } // hessian/3bb3 if ("".equals(type)) { @@ -2643,6 +2652,11 @@ public Object readObject() case 'M': { String type = readType(); + // add by zhiyuan @2018-7-10 + ClassNameResolver resolver = findSerializerFactory().getClassNameResolver(); + if (resolver != null) { + type = resolver.resolve(type); + } return findSerializerFactory().readMap(this, type); } diff --git a/src/main/java/com/caucho/hessian/io/HessianInput.java b/src/main/java/com/caucho/hessian/io/HessianInput.java index 8ee3cf7..b1c5bfc 100644 --- a/src/main/java/com/caucho/hessian/io/HessianInput.java +++ b/src/main/java/com/caucho/hessian/io/HessianInput.java @@ -48,6 +48,8 @@ package com.caucho.hessian.io; +import com.alipay.hessian.ClassNameResolver; + import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; @@ -137,6 +139,19 @@ public SerializerFactory getSerializerFactory() return _serializerFactory; } + /** + * Gets the serializer factory, creating a default if necessary. + */ + public final SerializerFactory findSerializerFactory() + { + SerializerFactory factory = _serializerFactory; + + if (factory == null) + _serializerFactory = factory = new SerializerFactory(); + + return factory; + } + /** * Initialize the hessian stream with the underlying input stream. */ @@ -1037,6 +1052,12 @@ public Object readObject(Class cl) case 'M': { String type = readType(); + // add by zhiyuan @2018-7-10 + ClassNameResolver resolver = findSerializerFactory().getClassNameResolver(); + if (resolver != null) { + type = resolver.resolve(type); + } + // hessian/3386 if ("".equals(type)) { Deserializer reader; @@ -1170,6 +1191,12 @@ public Object readObject() case 'M': { String type = readType(); + // add by zhiyuan @2018-7-10 + ClassNameResolver resolver = findSerializerFactory().getClassNameResolver(); + if (resolver != null) { + type = resolver.resolve(type); + } + return _serializerFactory.readMap(this, type); } diff --git a/src/test/java/com/alipay/hessian/ClassNameResolverTest.java b/src/test/java/com/alipay/hessian/ClassNameResolverTest.java index 2da95c3..67f40fd 100644 --- a/src/test/java/com/alipay/hessian/ClassNameResolverTest.java +++ b/src/test/java/com/alipay/hessian/ClassNameResolverTest.java @@ -46,7 +46,7 @@ public void test() throws Exception { boolean error = false; try { - resolver.resolve("java.lang.Thread"); + resolver.resolve("java.security.SignedObject"); } catch (Exception e) { error = true; } diff --git a/src/test/java/com/alipay/hessian/internal/InternalNameBlackListFilterTest.java b/src/test/java/com/alipay/hessian/internal/InternalNameBlackListFilterTest.java index 515d061..50d107c 100644 --- a/src/test/java/com/alipay/hessian/internal/InternalNameBlackListFilterTest.java +++ b/src/test/java/com/alipay/hessian/internal/InternalNameBlackListFilterTest.java @@ -32,7 +32,7 @@ public void testAll() { String className = null; boolean pass = true; try { - filter.resolve("org.apache.commons.beanutils.xxx"); + filter.resolve("java.util.ServiceLoader$LazyIterator.xxx"); } catch (Exception e) { pass = false; } diff --git a/src/test/java/com/caucho/hessian/test/SimpleDataGenerator.java b/src/test/java/com/caucho/hessian/test/SimpleDataGenerator.java index 60049fc..ca46393 100644 --- a/src/test/java/com/caucho/hessian/test/SimpleDataGenerator.java +++ b/src/test/java/com/caucho/hessian/test/SimpleDataGenerator.java @@ -685,7 +685,7 @@ public Object generateGenericObject_2b() { } public Object generateObject_3() { - TestCons cons = new TestCons(); + SimpleTestCons cons = new SimpleTestCons(); cons.setFirst("a"); cons.setRest(cons); @@ -694,7 +694,7 @@ public Object generateObject_3() { } public Object generateGenericObject_3() { - GenericObject gobj = new GenericObject(TestCons.class.getName()); + GenericObject gobj = new GenericObject(SimpleTestCons.class.getName()); gobj.putField("_first", "a"); gobj.putField("_rest", gobj); return gobj; diff --git a/src/test/java/com/caucho/hessian/test/TestCons.java b/src/test/java/com/caucho/hessian/test/SimpleTestCons.java similarity index 82% rename from src/test/java/com/caucho/hessian/test/TestCons.java rename to src/test/java/com/caucho/hessian/test/SimpleTestCons.java index fe6a5de..abcec0d 100644 --- a/src/test/java/com/caucho/hessian/test/TestCons.java +++ b/src/test/java/com/caucho/hessian/test/SimpleTestCons.java @@ -21,18 +21,18 @@ /** * Cons-cell for testing */ -public class TestCons implements java.io.Serializable { +public class SimpleTestCons implements java.io.Serializable { private Object _first; private Object _rest; - public TestCons() { + public SimpleTestCons() { } - public TestCons(Object first) { + public SimpleTestCons(Object first) { _first = first; } - public TestCons(Object first, Object rest) { + public SimpleTestCons(Object first, Object rest) { _first = first; _rest = rest; } @@ -72,15 +72,15 @@ public String toString(HashMap map) { StringBuilder sb = new StringBuilder(); sb.append(getClass().getSimpleName()).append("["); - if (_first instanceof TestCons) - sb.append(((TestCons) _first).toString(map)); + if (_first instanceof SimpleTestCons) + sb.append(((SimpleTestCons) _first).toString(map)); else sb.append(_first); sb.append(","); - if (_rest instanceof TestCons) - sb.append(((TestCons) _rest).toString(map)); + if (_rest instanceof SimpleTestCons) + sb.append(((SimpleTestCons) _rest).toString(map)); else sb.append(_rest); diff --git a/tools/ci/.travis.settings.xml b/tools/ci/.travis.settings.xml new file mode 100644 index 0000000..ddd1cfe --- /dev/null +++ b/tools/ci/.travis.settings.xml @@ -0,0 +1,138 @@ + + + + + + standard-with-extra-repos + + true + + + + + central + Central Repository + http://repo1.maven.org/maven2 + + true + always + + + false + always + + + + + central2 + Central Repository 2 + http://repo1.maven.apache.org/maven2 + + true + always + + + false + always + + + + + sonatype + OSS Sonatype repo (releases) + + true + always + warn + + + false + never + fail + + https://oss.sonatype.org/content/repositories/releases/ + + + + sonatype-snapshots + OSS Sonatype repo (snapshots) + + false + always + warn + + + true + never + fail + + https://oss.sonatype.org/content/repositories/snapshots/ + + + + sonatype-apache + Apache repo (releases) + + true + always + warn + + + false + never + fail + + https://repository.apache.org/releases/ + + + + apache-snapshots + ASF repo (snapshots) + + false + never + warn + + + true + always + fail + + https://repository.apache.org/snapshots/ + + + + + + central + + http://repo1.maven.org/maven2 + + true + always + + + false + always + + + + + central2 + + http://repo1.maven.apache.org/maven2 + + true + always + + + false + always + + + + + + \ No newline at end of file