From eebea031d4d6f0a079c3d26845d96ad50c3aaccd Mon Sep 17 00:00:00 2001 From: wenshao Date: Mon, 11 Dec 2017 10:40:55 +0800 Subject: [PATCH] bug fixed autoType denyList check. --- .../alibaba/fastjson/parser/ParserConfig.java | 151 ++++++++++++------ .../json/bvt/parser/deser/deny/DenyTest.java | 19 +++ 2 files changed, 120 insertions(+), 50 deletions(-) diff --git a/src/main/java/com/alibaba/fastjson/parser/ParserConfig.java b/src/main/java/com/alibaba/fastjson/parser/ParserConfig.java index 8e11868e71..38b5667d06 100644 --- a/src/main/java/com/alibaba/fastjson/parser/ParserConfig.java +++ b/src/main/java/com/alibaba/fastjson/parser/ParserConfig.java @@ -38,21 +38,7 @@ import java.nio.charset.Charset; import java.security.AccessControlException; import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Calendar; -import java.util.Collection; -import java.util.Currency; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Properties; -import java.util.Set; -import java.util.TimeZone; -import java.util.TreeMap; -import java.util.UUID; +import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.atomic.AtomicBoolean; @@ -69,6 +55,8 @@ import com.alibaba.fastjson.parser.deserializer.*; import com.alibaba.fastjson.serializer.*; import com.alibaba.fastjson.util.*; +import com.alibaba.fastjson.util.IdentityHashMap; +import com.alibaba.fastjson.util.ServiceLoader; import javax.sql.DataSource; import javax.xml.datatype.XMLGregorianCalendar; @@ -127,13 +115,49 @@ public static ParserConfig getGlobalInstance() { private static boolean jdk8Error = false; private boolean autoTypeSupport = AUTO_SUPPORT; - private String[] denyList = "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.apache.xalan,org.codehaus.groovy.runtime,org.hibernate,org.jboss,org.mozilla.javascript,org.python.core,org.springframework".split(","); - private String[] acceptList = AUTO_TYPE_ACCEPT_LIST; + private long[] denyHashCodes; + private long[] acceptHashCodes; + public final boolean fieldBased; public boolean compatibleWithJavaBean = TypeUtils.compatibleWithJavaBean; + { + denyHashCodes = new long[]{ + -8720046426850100497L, + -8109300701639721088L, + -7966123100503199569L, + -7766605818834748097L, + -6835437086156813536L, + -4082057040235125754L, + -3979025623072794412L, + -2364987994247679115L, + -1872417015366588117L, + -254670111376247151L, + 33238344207745342L, + 313864100207897507L, + 1203232727967308606L, + 3547627781654598988L, + 3730752432285826863L, + 4147696707147271408L, + 5450448828334921485L, + 5751393439502795295L, + 5944107969236155580L, + 6742705432718011780L, + 7179336928365889465L, + 7442624256860549330L, + 8838294710098435315L + }; + + long[] hashCodes = new long[AUTO_TYPE_ACCEPT_LIST.length]; + for (int i = 0; i < AUTO_TYPE_ACCEPT_LIST.length; i++) { + hashCodes[i] = TypeUtils.fnv1a_64(AUTO_TYPE_ACCEPT_LIST[i]); + } + Arrays.sort(hashCodes); + acceptHashCodes = hashCodes; + } + public ParserConfig(){ this(false); } @@ -818,16 +842,16 @@ public void addDeny(String name) { return; } - for (String item : denyList) { - if (name.equals(item)) { - return; // skip duplication - } + long hash = TypeUtils.fnv1a_64(name); + if (Arrays.binarySearch(this.denyHashCodes, hash) >= 0) { + return; } - String[] denyList = new String[this.denyList.length + 1]; - System.arraycopy(this.denyList, 0, denyList, 0, this.denyList.length); - denyList[denyList.length - 1] = name; - this.denyList = denyList; + long[] hashCodes = new long[this.denyHashCodes.length + 1]; + hashCodes[hashCodes.length - 1] = hash; + System.arraycopy(this.denyHashCodes, 0, hashCodes, 0, this.denyHashCodes.length); + Arrays.sort(hashCodes); + this.denyHashCodes = hashCodes; } public void addAccept(String name) { @@ -835,16 +859,16 @@ public void addAccept(String name) { return; } - for (String item : acceptList) { - if (name.equals(item)) { - return; // skip duplication - } + long hash = TypeUtils.fnv1a_64(name); + if (Arrays.binarySearch(this.acceptHashCodes, hash) >= 0) { + return; } - String[] acceptList = new String[this.acceptList.length + 1]; - System.arraycopy(this.acceptList, 0, acceptList, 0, this.acceptList.length); - acceptList[acceptList.length - 1] = name; - this.acceptList = acceptList; + long[] hashCodes = new long[this.acceptHashCodes.length + 1]; + hashCodes[hashCodes.length - 1] = hash; + System.arraycopy(this.acceptHashCodes, 0, hashCodes, 0, this.acceptHashCodes.length); + Arrays.sort(hashCodes); + this.acceptHashCodes = hashCodes; } public Class checkAutoType(String typeName, Class expectClass) { @@ -856,27 +880,50 @@ public Class checkAutoType(String typeName, Class expectClass, int feature return null; } - if (typeName.length() >= 128) { + if (typeName.length() >= 128 || typeName.length() < 3) { throw new JSONException("autoType is not support. " + typeName); } - final String className = typeName.replace('$', '.'); + String className = typeName.replace('$', '.'); Class clazz = null; + if (className.charAt(0) == 'L' && className.charAt(className.length() - 1) == ';') { + className = className.substring(1, className.length() - 1); + } + + final long BASIC = 0xcbf29ce484222325L; + final long PRIME = 0x100000001b3L; + + long hash3 = BASIC; + { + char c = className.charAt(0); + hash3 ^= c; + hash3 *= PRIME; + } + { + char c = className.charAt(1); + hash3 ^= c; + hash3 *= PRIME; + } + { + char c = className.charAt(2); + hash3 ^= c; + hash3 *= PRIME; + } + if (autoTypeSupport || expectClass != null) { - for (int i = 0; i < acceptList.length; ++i) { - String accept = acceptList[i]; - if (className.startsWith(accept)) { + long hash = hash3; + for (int i = 3; i < className.length(); ++i) { + char c = className.charAt(i); + hash ^= c; + hash *= PRIME; + if (Arrays.binarySearch(acceptHashCodes, hash) >= 0) { clazz = TypeUtils.loadClass(typeName, defaultClassLoader, false); if (clazz != null) { return clazz; } } - } - - for (int i = 0; i < denyList.length; ++i) { - String deny = denyList[i]; - if (className.startsWith(deny) && TypeUtils.getClassFromMapping(typeName) == null) { + if (Arrays.binarySearch(denyHashCodes, hash) >= 0 && TypeUtils.getClassFromMapping(typeName) == null) { throw new JSONException("autoType is not support. " + typeName); } } @@ -901,15 +948,17 @@ public Class checkAutoType(String typeName, Class expectClass, int feature } if (!autoTypeSupport) { - for (int i = 0; i < denyList.length; ++i) { - String deny = denyList[i]; - if (className.startsWith(deny)) { + long hash = hash3; + for (int i = 3; i < className.length(); ++i) { + char c = className.charAt(i); + hash ^= c; + hash *= PRIME; + + if (Arrays.binarySearch(denyHashCodes, hash) >= 0) { throw new JSONException("autoType is not support. " + typeName); } - } - for (int i = 0; i < acceptList.length; ++i) { - String accept = acceptList[i]; - if (className.startsWith(accept)) { + + if (Arrays.binarySearch(acceptHashCodes, hash) >= 0) { if (clazz == null) { clazz = TypeUtils.loadClass(typeName, defaultClassLoader, false); } @@ -917,9 +966,11 @@ public Class checkAutoType(String typeName, Class expectClass, int feature if (expectClass != null && expectClass.isAssignableFrom(clazz)) { throw new JSONException("type not match. " + typeName + " -> " + expectClass.getName()); } + return clazz; } } + } if (clazz == null) { diff --git a/src/test/java/com/alibaba/json/bvt/parser/deser/deny/DenyTest.java b/src/test/java/com/alibaba/json/bvt/parser/deser/deny/DenyTest.java index 3a52c33d40..9d375d81cd 100644 --- a/src/test/java/com/alibaba/json/bvt/parser/deser/deny/DenyTest.java +++ b/src/test/java/com/alibaba/json/bvt/parser/deser/deny/DenyTest.java @@ -30,6 +30,25 @@ public void test_0() throws Exception { JSON.parseObject(text, B.class, config, JSON.DEFAULT_PARSER_FEATURE); } + public void test_1() throws Exception { + String text = "{}"; + + ParserConfig config = new ParserConfig(); + + config.addDeny(null); + config.addDeny("com.alibaba.json.bvt.parser.deser.deny.DenyTest.B"); + + Exception error = null; + try { + JSON.parseObject("{\"@type\":\"Lcom.alibaba.json.bvt.parser.deser.deny.DenyTest$B;\"}", Object.class, config, JSON.DEFAULT_PARSER_FEATURE); + } catch (JSONException ex) { + error = ex; + } + Assert.assertNotNull(error); + + JSON.parseObject(text, B.class, config, JSON.DEFAULT_PARSER_FEATURE); + } + public static class B {