| package com.fasterxml.jackson.databind.jsontype.impl; |
| |
| import java.util.Collections; |
| import java.util.HashSet; |
| import java.util.Set; |
| |
| import com.fasterxml.jackson.databind.DeserializationContext; |
| import com.fasterxml.jackson.databind.JavaType; |
| import com.fasterxml.jackson.databind.JsonMappingException; |
| |
| /** |
| * Helper class used to encapsulate rules that determine subtypes that |
| * are invalid to use, even with default typing, mostly due to security |
| * concerns. |
| * Used by <code>BeanDeserializerFacotry</code> |
| * |
| * @since 2.8.11 |
| */ |
| public class SubTypeValidator |
| { |
| protected final static String PREFIX_SPRING = "org.springframework."; |
| |
| protected final static String PREFIX_C3P0 = "com.mchange.v2.c3p0."; |
| |
| /** |
| * Set of well-known "nasty classes", deserialization of which is considered dangerous |
| * and should (and is) prevented by default. |
| */ |
| protected final static Set<String> DEFAULT_NO_DESER_CLASS_NAMES; |
| static { |
| Set<String> s = new HashSet<String>(); |
| // Courtesy of [https://github.com/kantega/notsoserial]: |
| // (and wrt [databind#1599]) |
| s.add("org.apache.commons.collections.functors.InvokerTransformer"); |
| s.add("org.apache.commons.collections.functors.InstantiateTransformer"); |
| s.add("org.apache.commons.collections4.functors.InvokerTransformer"); |
| s.add("org.apache.commons.collections4.functors.InstantiateTransformer"); |
| s.add("org.codehaus.groovy.runtime.ConvertedClosure"); |
| s.add("org.codehaus.groovy.runtime.MethodClosure"); |
| s.add("org.springframework.beans.factory.ObjectFactory"); |
| s.add("com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl"); |
| s.add("org.apache.xalan.xsltc.trax.TemplatesImpl"); |
| // [databind#1680]: may or may not be problem, take no chance |
| s.add("com.sun.rowset.JdbcRowSetImpl"); |
| // [databind#1737]; JDK provided |
| s.add("java.util.logging.FileHandler"); |
| s.add("java.rmi.server.UnicastRemoteObject"); |
| // [databind#1737]; 3rd party |
| //s.add("org.springframework.aop.support.AbstractBeanFactoryPointcutAdvisor"); // deprecated by [databind#1855] |
| s.add("org.springframework.beans.factory.config.PropertyPathFactoryBean"); |
| |
| // s.add("com.mchange.v2.c3p0.JndiRefForwardingDataSource"); // deprecated by [databind#1931] |
| // s.add("com.mchange.v2.c3p0.WrapperConnectionPoolDataSource"); // - "" - |
| // [databind#1855]: more 3rd party |
| s.add("org.apache.tomcat.dbcp.dbcp2.BasicDataSource"); |
| s.add("com.sun.org.apache.bcel.internal.util.ClassLoader"); |
| // [databind#2032]: more 3rd party; data exfiltration via xml parsed ext entities |
| s.add("org.apache.ibatis.parsing.XPathParser"); |
| |
| // [databind#2052]: Jodd-db, with jndi/ldap lookup |
| s.add("jodd.db.connection.DataSourceConnectionProvider"); |
| |
| // [databind#2058]: Oracle JDBC driver, with jndi/ldap lookup |
| s.add("oracle.jdbc.connector.OracleManagedConnectionFactory"); |
| s.add("oracle.jdbc.rowset.OracleJDBCRowSet"); |
| |
| DEFAULT_NO_DESER_CLASS_NAMES = Collections.unmodifiableSet(s); |
| } |
| |
| /** |
| * Set of class names of types that are never to be deserialized. |
| */ |
| protected Set<String> _cfgIllegalClassNames = DEFAULT_NO_DESER_CLASS_NAMES; |
| |
| private final static SubTypeValidator instance = new SubTypeValidator(); |
| |
| protected SubTypeValidator() { } |
| |
| public static SubTypeValidator instance() { return instance; } |
| |
| public void validateSubType(DeserializationContext ctxt, JavaType type) throws JsonMappingException |
| { |
| // There are certain nasty classes that could cause problems, mostly |
| // via default typing -- catch them here. |
| final Class<?> raw = type.getRawClass(); |
| String full = raw.getName(); |
| |
| main_check: |
| do { |
| if (_cfgIllegalClassNames.contains(full)) { |
| break; |
| } |
| |
| // 18-Dec-2017, tatu: As per [databind#1855], need bit more sophisticated handling |
| // for some Spring framework types |
| // 05-Jan-2017, tatu: ... also, only applies to classes, not interfaces |
| if (raw.isInterface()) { |
| ; |
| } else if (full.startsWith(PREFIX_SPRING)) { |
| for (Class<?> cls = raw; (cls != null) && (cls != Object.class); cls = cls.getSuperclass()){ |
| String name = cls.getSimpleName(); |
| // looking for "AbstractBeanFactoryPointcutAdvisor" but no point to allow any is there? |
| if ("AbstractPointcutAdvisor".equals(name) |
| // ditto for "FileSystemXmlApplicationContext": block all ApplicationContexts |
| || "AbstractApplicationContext".equals(name)) { |
| break main_check; |
| } |
| } |
| } else if (full.startsWith(PREFIX_C3P0)) { |
| // [databind#1737]; more 3rd party |
| // s.add("com.mchange.v2.c3p0.JndiRefForwardingDataSource"); |
| // s.add("com.mchange.v2.c3p0.WrapperConnectionPoolDataSource"); |
| // [databind#1931]; more 3rd party |
| // com.mchange.v2.c3p0.ComboPooledDataSource |
| // com.mchange.v2.c3p0.debug.AfterCloseLoggingComboPooledDataSource |
| if (full.endsWith("DataSource")) { |
| break main_check; |
| } |
| } |
| return; |
| } while (false); |
| |
| throw JsonMappingException.from(ctxt, |
| String.format("Illegal type (%s) to deserialize: prevented for security reasons", full)); |
| } |
| } |