This is an automated email from the ASF dual-hosted git repository.

liujun pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/dubbo.git


The following commit(s) were added to refs/heads/master by this push:
     new 4d3a318  Add serialize class checker (#7436)
4d3a318 is described below

commit 4d3a318fb68067fd5f174e064e1d7b54c62cee9c
Author: Albumen Kevin <[email protected]>
AuthorDate: Fri Mar 26 16:08:55 2021 +0800

    Add serialize class checker (#7436)
---
 .../common/beanutil/JavaBeanSerializeUtil.java     |   2 +
 .../dubbo/common/constants/CommonConstants.java    |  10 ++
 .../org/apache/dubbo/common/utils/PojoUtils.java   |   1 +
 .../dubbo/common/utils/SerializeClassChecker.java  | 150 ++++++++++++++++++
 .../main/resources/security/serialize.blockedlist  | 167 +++++++++++++++++++++
 .../common/utils/SerializeClassCheckerTest.java    | 105 +++++++++++++
 .../org/apache/dubbo/rpc/filter/GenericFilter.java |  21 ++-
 .../apache/dubbo/rpc/filter/GenericFilterTest.java |   4 +
 .../rpc/protocol/hessian/HessianProtocolTest.java  |   6 +-
 9 files changed, 463 insertions(+), 3 deletions(-)

diff --git 
a/dubbo-common/src/main/java/org/apache/dubbo/common/beanutil/JavaBeanSerializeUtil.java
 
b/dubbo-common/src/main/java/org/apache/dubbo/common/beanutil/JavaBeanSerializeUtil.java
index 8121d65..c4463a2 100644
--- 
a/dubbo-common/src/main/java/org/apache/dubbo/common/beanutil/JavaBeanSerializeUtil.java
+++ 
b/dubbo-common/src/main/java/org/apache/dubbo/common/beanutil/JavaBeanSerializeUtil.java
@@ -20,6 +20,7 @@ import org.apache.dubbo.common.logger.Logger;
 import org.apache.dubbo.common.logger.LoggerFactory;
 import org.apache.dubbo.common.utils.LogHelper;
 import org.apache.dubbo.common.utils.ReflectUtils;
+import org.apache.dubbo.common.utils.SerializeClassChecker;
 
 import java.lang.reflect.Array;
 import java.lang.reflect.Constructor;
@@ -464,6 +465,7 @@ public final class JavaBeanSerializeUtil {
         if (isReferenceType(name)) {
             name = name.substring(1, name.length() - 1);
         }
+        SerializeClassChecker.getInstance().validateClass(name);
         return Class.forName(name, false, loader);
     }
 
diff --git 
a/dubbo-common/src/main/java/org/apache/dubbo/common/constants/CommonConstants.java
 
b/dubbo-common/src/main/java/org/apache/dubbo/common/constants/CommonConstants.java
index 3f234dd..e4f6af8 100644
--- 
a/dubbo-common/src/main/java/org/apache/dubbo/common/constants/CommonConstants.java
+++ 
b/dubbo-common/src/main/java/org/apache/dubbo/common/constants/CommonConstants.java
@@ -371,4 +371,14 @@ public interface CommonConstants {
     String CLASSPATH_URL_PREFIX = "classpath:";
 
     String DEFAULT_VERSION = "0.0.0";
+
+    String CLASS_DESERIALIZE_BLOCK_ALL = 
"dubbo.security.serialize.blockAllClassExceptAllow";
+
+    String CLASS_DESERIALIZE_ALLOWED_LIST = 
"dubbo.security.serialize.allowedClassList";
+
+    String CLASS_DESERIALIZE_BLOCKED_LIST = 
"dubbo.security.serialize.blockedClassList";
+
+    String ENABLE_NATIVE_JAVA_GENERIC_SERIALIZE = 
"dubbo.security.serialize.generic.native-java-enable";
+
+    String SERIALIZE_BLOCKED_LIST_FILE_PATH = "security/serialize.blockedlist";
 }
diff --git 
a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/PojoUtils.java 
b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/PojoUtils.java
index 80e4ad3..29328b2 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/PojoUtils.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/PojoUtils.java
@@ -387,6 +387,7 @@ public class PojoUtils {
         if (pojo instanceof Map<?, ?> && type != null) {
             Object className = ((Map<Object, Object>) pojo).get("class");
             if (className instanceof String) {
+                SerializeClassChecker.getInstance().validateClass((String) 
className);
                 try {
                     type = ClassUtils.forName((String) className);
                 } catch (ClassNotFoundException e) {
diff --git 
a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/SerializeClassChecker.java
 
b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/SerializeClassChecker.java
new file mode 100644
index 0000000..b75ae65
--- /dev/null
+++ 
b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/SerializeClassChecker.java
@@ -0,0 +1,150 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.common.utils;
+
+import org.apache.dubbo.common.beanutil.JavaBeanSerializeUtil;
+import org.apache.dubbo.common.constants.CommonConstants;
+import org.apache.dubbo.common.logger.Logger;
+import org.apache.dubbo.common.logger.LoggerFactory;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Locale;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicLong;
+
+public class SerializeClassChecker {
+    private static final Logger logger = 
LoggerFactory.getLogger(SerializeClassChecker.class);
+
+    private static volatile SerializeClassChecker INSTANCE = null;
+
+    private final boolean BLOCK_ALL_CLASS_EXCEPT_ALLOW;
+    private final Set<String> CLASS_DESERIALIZE_ALLOWED_SET = new 
ConcurrentHashSet<>();
+    private final Set<String> CLASS_DESERIALIZE_BLOCKED_SET = new 
ConcurrentHashSet<>();
+
+    private final Object CACHE = new Object();
+    private final LFUCache<String, Object> CLASS_ALLOW_LFU_CACHE = new 
LFUCache<>();
+    private final LFUCache<String, Object> CLASS_BLOCK_LFU_CACHE = new 
LFUCache<>();
+
+    private final AtomicLong counter = new AtomicLong(0);
+
+    private SerializeClassChecker() {
+        String blockAllClassExceptAllow = 
System.getProperty(CommonConstants.CLASS_DESERIALIZE_BLOCK_ALL, "false");
+        BLOCK_ALL_CLASS_EXCEPT_ALLOW = 
Boolean.parseBoolean(blockAllClassExceptAllow);
+
+        String[] lines;
+        try {
+            ClassLoader classLoader = 
ClassUtils.getClassLoader(JavaBeanSerializeUtil.class);
+            if (classLoader != null) {
+                lines = 
IOUtils.readLines(classLoader.getResourceAsStream(CommonConstants.SERIALIZE_BLOCKED_LIST_FILE_PATH));
+            } else {
+                lines = 
IOUtils.readLines(ClassLoader.getSystemResourceAsStream(CommonConstants.SERIALIZE_BLOCKED_LIST_FILE_PATH));
+            }
+            for (String line : lines) {
+                line = line.trim();
+                if (StringUtils.isEmpty(line) || line.startsWith("#")) {
+                    continue;
+                }
+                CLASS_DESERIALIZE_BLOCKED_SET.add(line);
+            }
+
+        } catch (IOException e) {
+            logger.error("Failed to load blocked class list! Will ignore 
default blocked list.", e);
+        }
+
+        String allowedClassList = 
System.getProperty(CommonConstants.CLASS_DESERIALIZE_ALLOWED_LIST, 
"").trim().toLowerCase(Locale.ROOT);
+        String blockedClassList = 
System.getProperty(CommonConstants.CLASS_DESERIALIZE_BLOCKED_LIST, 
"").trim().toLowerCase(Locale.ROOT);
+
+        if (StringUtils.isNotEmpty(allowedClassList)) {
+            String[] classStrings = allowedClassList.trim().split(",");
+            CLASS_DESERIALIZE_ALLOWED_SET.addAll(Arrays.asList(classStrings));
+        }
+
+        if (StringUtils.isNotEmpty(blockedClassList)) {
+            String[] classStrings = blockedClassList.trim().split(",");
+            CLASS_DESERIALIZE_BLOCKED_SET.addAll(Arrays.asList(classStrings));
+        }
+
+    }
+
+    public static SerializeClassChecker getInstance() {
+        if (INSTANCE == null) {
+            synchronized (SerializeClassChecker.class) {
+                if (INSTANCE == null) {
+                    INSTANCE = new SerializeClassChecker();
+                }
+            }
+        }
+        return INSTANCE;
+    }
+
+    /**
+     * For ut only
+     */
+    @Deprecated
+    protected static void clearInstance() {
+        INSTANCE = null;
+    }
+
+    /**
+     * Check if a class is in block list, using prefix match
+     *
+     * @throws IllegalArgumentException if class is blocked
+     * @param name class name ( all are convert to lower case )
+     */
+    public void validateClass(String name) {
+        name = name.toLowerCase(Locale.ROOT);
+        if (CACHE == CLASS_ALLOW_LFU_CACHE.get(name)) {
+            return;
+        }
+
+        if (CACHE == CLASS_BLOCK_LFU_CACHE.get(name)) {
+            error(name);
+        }
+
+        for (String allowedPrefix : CLASS_DESERIALIZE_ALLOWED_SET) {
+            if (name.startsWith(allowedPrefix)) {
+                CLASS_ALLOW_LFU_CACHE.put(name, CACHE);
+                return;
+            }
+        }
+
+        for (String blockedPrefix : CLASS_DESERIALIZE_BLOCKED_SET) {
+            if (BLOCK_ALL_CLASS_EXCEPT_ALLOW || 
name.startsWith(blockedPrefix)) {
+                CLASS_BLOCK_LFU_CACHE.put(name, CACHE);
+                error(name);
+            }
+        }
+
+        CLASS_ALLOW_LFU_CACHE.put(name, CACHE);
+    }
+
+    private void error(String name) {
+        String notice = "Trigger the safety barrier! " +
+                "Catch not allowed serialize class. " +
+                "Class name: " + name + " . " +
+                "This means currently maybe being attacking by others." +
+                "If you are sure this is a mistake, " +
+                "please add this class name to `" + 
CommonConstants.CLASS_DESERIALIZE_ALLOWED_LIST +
+                "` as a system environment property.";
+        if (counter.incrementAndGet() % 1000 == 0 || counter.get() < 100) {
+            logger.error(notice);
+        }
+        throw new IllegalArgumentException(notice);
+    }
+
+}
diff --git a/dubbo-common/src/main/resources/security/serialize.blockedlist 
b/dubbo-common/src/main/resources/security/serialize.blockedlist
new file mode 100644
index 0000000..de0b68d
--- /dev/null
+++ b/dubbo-common/src/main/resources/security/serialize.blockedlist
@@ -0,0 +1,167 @@
+#
+#
+#   Licensed to the Apache Software Foundation (ASF) under one or more
+#   contributor license agreements.  See the NOTICE file distributed with
+#   this work for additional information regarding copyright ownership.
+#   The ASF licenses this file to You under the Apache License, Version 2.0
+#   (the "License"); you may not use this file except in compliance with
+#   the License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#   Unless required by applicable law or agreed to in writing, software
+#   distributed under the License is distributed on an "AS IS" BASIS,
+#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#   See the License for the specific language governing permissions and
+#   limitations under the License.
+#
+#
+aj.org.objectweb.asm.
+br.com.anteros.
+ch.qos.logback.
+clojure.core$constantly
+clojure.main$eval_opt
+com.alibaba.citrus.springext.support.parser.abstractnamedproxybeandefinitionparser$proxytargetfactory
+com.alibaba.citrus.springext.util.springextutil.abstractproxy
+com.alibaba.druid.pool.druiddatasource
+com.alibaba.druid.stat.jdbcdatasourcestat
+com.alibaba.fastjson.annotation
+com.alipay.custrelation.service.model.redress.pair
+com.caucho.
+com.ibatis.
+com.mchange
+com.mysql.cj.jdbc.admin.
+com.mysql.cj.jdbc.mysqlconnectionpooldatasource
+com.mysql.cj.jdbc.mysqldatasource
+com.mysql.cj.jdbc.mysqlxadatasource
+com.mysql.cj.log.
+com.p6spy.engine.
+com.rometools.rome.feed.impl.equalsbean
+com.rometools.rome.feed.impl.tostringbean
+com.sun.
+com.taobao.eagleeye.wrapper
+com.zaxxer.hikari.
+flex.messaging.util.concurrent.
+java.awt.i
+java.awt.p
+java.beans.expression
+java.io.closeable
+java.io.serializable
+java.lang.autocloseable
+java.lang.class
+java.lang.cloneable
+java.lang.iterable
+java.lang.object
+java.lang.readable
+java.lang.runnable
+java.lang.thread
+java.lang.unixprocess
+java.net.inetaddress
+java.net.socket
+java.net.url
+java.rmi
+java.security.signedobject
+java.util.collection
+java.util.eventlistener
+java.util.jar.
+java.util.logging.
+java.util.prefs.
+java.util.serviceloader$lazyiterator
+javassist.
+javax.activation.
+javax.imageio.imageio$containsfilter
+javax.imageio.spi.serviceregistry
+javax.management.
+javax.naming.
+javax.net.
+javax.print.
+javax.script.
+javax.sound.
+javax.swing.j
+javax.tools.
+javax.xml
+jdk.internal.
+jodd.db.connection.
+junit.
+net.bytebuddy.dynamic.loading.bytearrayclassloader
+net.sf.cglib.
+net.sf.ehcache.hibernate.
+net.sf.ehcache.transaction.manager.
+oracle.jdbc.
+oracle.jms.aq
+oracle.net
+org.aoju.bus.proxy.provider.
+org.apache.activemq.activemqconnectionfactory
+org.apache.activemq.activemqxaconnectionfactory
+org.apache.activemq.jms.pool.
+org.apache.activemq.pool.
+org.apache.activemq.spring.
+org.apache.aries.transaction.
+org.apache.axis2.jaxws.spi.handler.
+org.apache.axis2.transport.jms.
+org.apache.bcel
+org.apache.carbondata.core.scan.expression.expressionresult
+org.apache.catalina.
+org.apache.cocoon.
+org.apache.commons.beanutils
+org.apache.commons.collections.comparators.
+org.apache.commons.collections.functors
+org.apache.commons.collections.functors.
+org.apache.commons.collections.transformer
+org.apache.commons.collections4.comparators
+org.apache.commons.collections4.functors
+org.apache.commons.collections4.transformer
+org.apache.commons.configuration
+org.apache.commons.dbcp
+org.apache.commons.fileupload
+org.apache.commons.jelly.
+org.apache.commons.logging.
+org.apache.commons.proxy.
+org.apache.cxf.jaxrs.provider.
+org.apache.hadoop.shaded.com.zaxxer.hikari.
+org.apache.http.auth.
+org.apache.http.conn.
+org.apache.http.cookie.
+org.apache.http.impl.
+org.apache.ibatis.datasource
+org.apache.ibatis.executor.
+org.apache.ibatis.javassist.
+org.apache.ibatis.ognl.
+org.apache.ibatis.parsing.
+org.apache.ibatis.reflection.
+org.apache.ibatis.scripting.
+org.apache.ignite.cache.jta.
+org.apache.log4j.
+org.apache.logging.
+org.apache.myfaces.context.servlet
+org.apache.openjpa.ee.
+org.apache.shiro.jndi.
+org.apache.shiro.realm.
+org.apache.tomcat
+org.apache.wicket.util
+org.apache.xalan
+org.apache.xbean.
+org.apache.xpath.xpathcontext
+org.codehaus.groovy.runtime
+org.codehaus.jackson.
+org.eclipse.jetty.
+org.geotools.filter.constantexpression
+org.h2.jdbcx.
+org.h2.server.
+org.hibernate
+org.javasimon.
+org.jaxen.
+org.jboss
+org.jdom.
+org.jdom2.transform.
+org.logicalcobwebs.
+org.mortbay.jetty.
+org.mozilla.javascript
+org.objectweb.asm.
+org.osjava.sj.
+org.python.core
+org.quartz.
+org.slf4j.
+org.springframework.
+org.yaml.snakeyaml.tokens.directivetoken
+sun.rmi.server.unicastref
\ No newline at end of file
diff --git 
a/dubbo-common/src/test/java/org/apache/dubbo/common/utils/SerializeClassCheckerTest.java
 
b/dubbo-common/src/test/java/org/apache/dubbo/common/utils/SerializeClassCheckerTest.java
new file mode 100644
index 0000000..b58f399
--- /dev/null
+++ 
b/dubbo-common/src/test/java/org/apache/dubbo/common/utils/SerializeClassCheckerTest.java
@@ -0,0 +1,105 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.common.utils;
+
+import org.apache.dubbo.common.constants.CommonConstants;
+
+import javassist.compiler.Javac;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import java.net.Socket;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Locale;
+
+public class SerializeClassCheckerTest {
+
+    @BeforeEach
+    public void setUp() {
+        SerializeClassChecker.clearInstance();
+    }
+
+    @Test
+    public void testCommon() {
+        SerializeClassChecker serializeClassChecker = 
SerializeClassChecker.getInstance();
+
+        for (int i = 0; i < 10; i++) {
+            serializeClassChecker.validateClass(List.class.getName());
+            serializeClassChecker.validateClass(LinkedList.class.getName());
+            serializeClassChecker.validateClass(Integer.class.getName());
+            serializeClassChecker.validateClass(int.class.getName());
+
+            
serializeClassChecker.validateClass(List.class.getName().toUpperCase(Locale.ROOT));
+            
serializeClassChecker.validateClass(LinkedList.class.getName().toUpperCase(Locale.ROOT));
+            
serializeClassChecker.validateClass(Integer.class.getName().toUpperCase(Locale.ROOT));
+            
serializeClassChecker.validateClass(int.class.getName().toUpperCase(Locale.ROOT));
+        }
+
+        Assertions.assertThrows(IllegalArgumentException.class, ()-> {
+            serializeClassChecker.validateClass(Socket.class.getName());
+        });
+    }
+
+    @Test
+    public void testAddAllow() {
+        System.setProperty(CommonConstants.CLASS_DESERIALIZE_ALLOWED_LIST, 
Socket.class.getName() + "," + Javac.class.getName());
+
+        SerializeClassChecker serializeClassChecker = 
SerializeClassChecker.getInstance();
+        for (int i = 0; i < 10; i++) {
+            serializeClassChecker.validateClass(Socket.class.getName());
+            serializeClassChecker.validateClass(Javac.class.getName());
+        }
+
+        System.clearProperty(CommonConstants.CLASS_DESERIALIZE_ALLOWED_LIST);
+    }
+
+    @Test
+    public void testAddBlock() {
+        System.setProperty(CommonConstants.CLASS_DESERIALIZE_BLOCKED_LIST, 
LinkedList.class.getName() + "," + Integer.class.getName());
+
+        SerializeClassChecker serializeClassChecker = 
SerializeClassChecker.getInstance();
+        for (int i = 0; i < 10; i++) {
+            Assertions.assertThrows(IllegalArgumentException.class, ()-> {
+                
serializeClassChecker.validateClass(LinkedList.class.getName());
+            });
+            Assertions.assertThrows(IllegalArgumentException.class, ()-> {
+                serializeClassChecker.validateClass(Integer.class.getName());
+            });
+        }
+
+        System.clearProperty(CommonConstants.CLASS_DESERIALIZE_BLOCKED_LIST);
+    }
+
+    @Test
+    public void testBlockAll() {
+        System.setProperty(CommonConstants.CLASS_DESERIALIZE_BLOCK_ALL, 
"true");
+        System.setProperty(CommonConstants.CLASS_DESERIALIZE_ALLOWED_LIST, 
LinkedList.class.getName());
+
+        SerializeClassChecker serializeClassChecker = 
SerializeClassChecker.getInstance();
+        for (int i = 0; i < 10; i++) {
+            serializeClassChecker.validateClass(LinkedList.class.getName());
+            Assertions.assertThrows(IllegalArgumentException.class, ()-> {
+                serializeClassChecker.validateClass(Integer.class.getName());
+            });
+        }
+
+        System.clearProperty(CommonConstants.CLASS_DESERIALIZE_BLOCK_ALL);
+        System.clearProperty(CommonConstants.CLASS_DESERIALIZE_ALLOWED_LIST);
+    }
+}
diff --git 
a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/GenericFilter.java
 
b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/GenericFilter.java
index 9c2ef94..2e6d3a8 100644
--- 
a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/GenericFilter.java
+++ 
b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/GenericFilter.java
@@ -19,11 +19,14 @@ package org.apache.dubbo.rpc.filter;
 import org.apache.dubbo.common.beanutil.JavaBeanAccessor;
 import org.apache.dubbo.common.beanutil.JavaBeanDescriptor;
 import org.apache.dubbo.common.beanutil.JavaBeanSerializeUtil;
+import org.apache.dubbo.common.config.Configuration;
 import org.apache.dubbo.common.constants.CommonConstants;
 import org.apache.dubbo.common.extension.Activate;
 import org.apache.dubbo.common.extension.ExtensionLoader;
 import org.apache.dubbo.common.io.UnsafeByteArrayInputStream;
 import org.apache.dubbo.common.io.UnsafeByteArrayOutputStream;
+import org.apache.dubbo.common.logger.Logger;
+import org.apache.dubbo.common.logger.LoggerFactory;
 import org.apache.dubbo.common.serialize.Serialization;
 import org.apache.dubbo.common.utils.PojoUtils;
 import org.apache.dubbo.common.utils.ReflectUtils;
@@ -35,6 +38,7 @@ import org.apache.dubbo.rpc.Result;
 import org.apache.dubbo.rpc.RpcContext;
 import org.apache.dubbo.rpc.RpcException;
 import org.apache.dubbo.rpc.RpcInvocation;
+import org.apache.dubbo.rpc.model.ApplicationModel;
 import org.apache.dubbo.rpc.service.GenericException;
 import org.apache.dubbo.rpc.service.GenericService;
 import org.apache.dubbo.rpc.support.ProtocolUtils;
@@ -54,6 +58,7 @@ import static org.apache.dubbo.rpc.Constants.GENERIC_KEY;
  */
 @Activate(group = CommonConstants.PROVIDER, order = -20000)
 public class GenericFilter implements Filter, Filter.Listener {
+    private static final Logger logger = 
LoggerFactory.getLogger(GenericFilter.class);
 
     @Override
     public Result invoke(Invoker<?> invoker, Invocation inv) throws 
RpcException {
@@ -71,7 +76,7 @@ public class GenericFilter implements Filter, Filter.Listener 
{
                     args = new Object[params.length];
                 }
 
-                if(types == null) {
+                if (types == null) {
                     types = new String[params.length];
                 }
 
@@ -90,6 +95,18 @@ public class GenericFilter implements Filter, 
Filter.Listener {
                         || ProtocolUtils.isGenericReturnRawResult(generic)) {
                     args = PojoUtils.realize(args, params, 
method.getGenericParameterTypes());
                 } else if (ProtocolUtils.isJavaGenericSerialization(generic)) {
+                    Configuration configuration = 
ApplicationModel.getEnvironment().getConfiguration();
+                    if 
(!configuration.getBoolean(CommonConstants.ENABLE_NATIVE_JAVA_GENERIC_SERIALIZE,
 false)) {
+                        String notice = "Trigger the safety barrier! " +
+                                "Native Java Serializer is not allowed by 
default." +
+                                "This means currently maybe being attacking by 
others. " +
+                                "If you are sure this is a mistake, " +
+                                "please set `" + 
CommonConstants.ENABLE_NATIVE_JAVA_GENERIC_SERIALIZE + "` enable in 
configuration! " +
+                                "Before doing so, please make sure you have 
configure JEP290 to prevent serialization attack.";
+                        logger.error(notice);
+                        throw new RpcException(new 
IllegalStateException(notice));
+                    }
+
                     for (int i = 0; i < args.length; i++) {
                         if (byte[].class == args[i].getClass()) {
                             try (UnsafeByteArrayInputStream is = new 
UnsafeByteArrayInputStream((byte[]) args[i])) {
@@ -205,7 +222,7 @@ public class GenericFilter implements Filter, 
Filter.Listener {
                             GENERIC_SERIALIZATION_PROTOBUF +
                             "] serialize result failed.", e);
                 }
-            } else if(ProtocolUtils.isGenericReturnRawResult(generic)) {
+            } else if (ProtocolUtils.isGenericReturnRawResult(generic)) {
                 return;
             } else {
                 
appResponse.setValue(PojoUtils.generalize(appResponse.getValue()));
diff --git 
a/dubbo-rpc/dubbo-rpc-api/src/test/java/org/apache/dubbo/rpc/filter/GenericFilterTest.java
 
b/dubbo-rpc/dubbo-rpc-api/src/test/java/org/apache/dubbo/rpc/filter/GenericFilterTest.java
index c49aa92..48ae217 100644
--- 
a/dubbo-rpc/dubbo-rpc-api/src/test/java/org/apache/dubbo/rpc/filter/GenericFilterTest.java
+++ 
b/dubbo-rpc/dubbo-rpc-api/src/test/java/org/apache/dubbo/rpc/filter/GenericFilterTest.java
@@ -17,6 +17,7 @@
 package org.apache.dubbo.rpc.filter;
 
 import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.constants.CommonConstants;
 import org.apache.dubbo.rpc.AppResponse;
 import org.apache.dubbo.rpc.AsyncRpcResult;
 import org.apache.dubbo.rpc.Invocation;
@@ -75,6 +76,8 @@ public class GenericFilterTest {
 
     @Test
     public void testInvokeWithJavaException() throws Exception {
+        // temporary enable native java generic serialize
+        
System.setProperty(CommonConstants.ENABLE_NATIVE_JAVA_GENERIC_SERIALIZE, 
"true");
         Assertions.assertThrows(RpcException.class, () -> {
             Method genericInvoke = GenericService.class.getMethods()[0];
 
@@ -95,6 +98,7 @@ public class GenericFilterTest {
 
             genericFilter.invoke(invoker, invocation);
         });
+        
System.clearProperty(CommonConstants.ENABLE_NATIVE_JAVA_GENERIC_SERIALIZE);
     }
 
     @Test
diff --git 
a/dubbo-rpc/dubbo-rpc-hessian/src/test/java/org/apache/dubbo/rpc/protocol/hessian/HessianProtocolTest.java
 
b/dubbo-rpc/dubbo-rpc-hessian/src/test/java/org/apache/dubbo/rpc/protocol/hessian/HessianProtocolTest.java
index a9bf02e..7ee98b3 100644
--- 
a/dubbo-rpc/dubbo-rpc-hessian/src/test/java/org/apache/dubbo/rpc/protocol/hessian/HessianProtocolTest.java
+++ 
b/dubbo-rpc/dubbo-rpc-hessian/src/test/java/org/apache/dubbo/rpc/protocol/hessian/HessianProtocolTest.java
@@ -19,6 +19,7 @@ package org.apache.dubbo.rpc.protocol.hessian;
 import org.apache.dubbo.common.URL;
 import org.apache.dubbo.common.beanutil.JavaBeanDescriptor;
 import org.apache.dubbo.common.beanutil.JavaBeanSerializeUtil;
+import org.apache.dubbo.common.constants.CommonConstants;
 import org.apache.dubbo.common.extension.ExtensionLoader;
 import org.apache.dubbo.common.serialize.ObjectInput;
 import org.apache.dubbo.common.serialize.ObjectOutput;
@@ -32,8 +33,8 @@ import org.apache.dubbo.rpc.ProxyFactory;
 import org.apache.dubbo.rpc.RpcContext;
 import org.apache.dubbo.rpc.RpcException;
 import org.apache.dubbo.rpc.protocol.hessian.HessianServiceImpl.MyException;
-
 import org.apache.dubbo.rpc.service.GenericService;
+
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Test;
 
@@ -86,6 +87,8 @@ public class HessianProtocolTest {
 
     @Test
     public void testGenericInvokeWithNativeJava() throws IOException, 
ClassNotFoundException {
+        // temporary enable native java generic serialize
+        
System.setProperty(CommonConstants.ENABLE_NATIVE_JAVA_GENERIC_SERIALIZE, 
"true");
         HessianServiceImpl server = new HessianServiceImpl();
         Assertions.assertFalse(server.isCalled());
         ProxyFactory proxyFactory = 
ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension();
@@ -110,6 +113,7 @@ public class HessianProtocolTest {
         Assertions.assertEquals("Hello, haha", objectInput.readObject());
         invoker.destroy();
         exporter.unexport();
+        
System.clearProperty(CommonConstants.ENABLE_NATIVE_JAVA_GENERIC_SERIALIZE);
     }
 
     @Test

Reply via email to