diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/constants/LoggerCodeConstants.java b/dubbo-common/src/main/java/org/apache/dubbo/common/constants/LoggerCodeConstants.java index f033d3941a..506ddadd32 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/common/constants/LoggerCodeConstants.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/constants/LoggerCodeConstants.java @@ -291,6 +291,8 @@ public interface LoggerCodeConstants { String PROTOCOL_FAILED_DECODE = "4-20"; + String PROTOCOL_UNTRUSTED_SERIALIZE_CLASS = "4-21"; + // Config module String CONFIG_FAILED_CONNECT_REGISTRY = "5-1"; diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/AllowClassNotifyListener.java b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/AllowClassNotifyListener.java index 20e37b62ee..2346e0dc2c 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/AllowClassNotifyListener.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/AllowClassNotifyListener.java @@ -20,7 +20,7 @@ import java.util.Set; public interface AllowClassNotifyListener { - SerializeCheckStatus DEFAULT_STATUS = SerializeCheckStatus.STRICT; + SerializeCheckStatus DEFAULT_STATUS = SerializeCheckStatus.WARN; void notify(SerializeCheckStatus status, Set prefixList); } diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/SerializeSecurityManager.java b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/SerializeSecurityManager.java index 2dd3432765..6cea23a58d 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/SerializeSecurityManager.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/SerializeSecurityManager.java @@ -16,10 +16,6 @@ */ package org.apache.dubbo.common.utils; -import org.apache.dubbo.common.logger.Logger; -import org.apache.dubbo.common.logger.LoggerFactory; -import org.apache.dubbo.rpc.model.FrameworkModel; - import java.io.IOException; import java.lang.reflect.Field; import java.lang.reflect.GenericArrayType; @@ -36,12 +32,18 @@ import java.util.List; import java.util.Set; import java.util.stream.Collectors; +import org.apache.dubbo.common.logger.ErrorTypeAwareLogger; +import org.apache.dubbo.common.logger.LoggerFactory; +import org.apache.dubbo.rpc.model.FrameworkModel; + import static org.apache.dubbo.common.constants.CommonConstants.SERIALIZE_ALLOW_LIST_FILE_PATH; +import static org.apache.dubbo.common.constants.LoggerCodeConstants.COMMON_IO_EXCEPTION; +import static org.apache.dubbo.common.constants.LoggerCodeConstants.INTERNAL_INTERRUPTED; public class SerializeSecurityManager { private final Set allowedPrefix = new LinkedHashSet<>(); - private final static Logger logger = LoggerFactory.getLogger(SerializeSecurityManager.class); + private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(SerializeSecurityManager.class); private final SerializeClassChecker checker = SerializeClassChecker.getInstance(); @@ -59,6 +61,7 @@ public class SerializeSecurityManager { .collect(Collectors.toList()); for (URL u : urls) { try { + logger.info("Read serialize allow list from " + u); String[] lines = IOUtils.readLines(u.openStream()); for (String line : lines) { line = line.trim(); @@ -68,11 +71,12 @@ public class SerializeSecurityManager { allowedPrefix.add(line); } } catch (IOException e) { - logger.error("Failed to load allow class list! Will ignore allow lis from " + u, e); + logger.error(COMMON_IO_EXCEPTION, "", "", "Failed to load allow class list! Will ignore allow lis from " + u, e); } } } catch (InterruptedException e) { - logger.error("Failed to load allow class list! Will ignore allow list from configuration.", e); + logger.error(INTERNAL_INTERRUPTED, "", "", "Failed to load allow class list! Will ignore allow list from configuration.", e); + Thread.currentThread().interrupt(); } } diff --git a/dubbo-serialization/dubbo-serialization-fastjson2/src/main/java/org/apache/dubbo/common/serialize/fastjson2/Fastjson2SecurityManager.java b/dubbo-serialization/dubbo-serialization-fastjson2/src/main/java/org/apache/dubbo/common/serialize/fastjson2/Fastjson2SecurityManager.java index 7259a0630d..e9334278c8 100644 --- a/dubbo-serialization/dubbo-serialization-fastjson2/src/main/java/org/apache/dubbo/common/serialize/fastjson2/Fastjson2SecurityManager.java +++ b/dubbo-serialization/dubbo-serialization-fastjson2/src/main/java/org/apache/dubbo/common/serialize/fastjson2/Fastjson2SecurityManager.java @@ -16,7 +16,11 @@ */ package org.apache.dubbo.common.serialize.fastjson2; -import org.apache.dubbo.common.logger.Logger; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +import org.apache.dubbo.common.logger.ErrorTypeAwareLogger; import org.apache.dubbo.common.logger.LoggerFactory; import org.apache.dubbo.common.utils.AllowClassNotifyListener; import org.apache.dubbo.common.utils.ConcurrentHashSet; @@ -28,18 +32,16 @@ import com.alibaba.fastjson2.filter.ContextAutoTypeBeforeHandler; import com.alibaba.fastjson2.filter.Filter; import com.alibaba.fastjson2.util.TypeUtils; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; - import static com.alibaba.fastjson2.util.TypeUtils.loadClass; +import static org.apache.dubbo.common.constants.LoggerCodeConstants.PROTOCOL_UNTRUSTED_SERIALIZE_CLASS; +import static org.apache.dubbo.common.utils.SerializeCheckStatus.STRICT; public class Fastjson2SecurityManager implements AllowClassNotifyListener { private Filter securityFilter = new Handler(AllowClassNotifyListener.DEFAULT_STATUS, new String[0]); - private final static Logger logger = LoggerFactory.getLogger(Fastjson2SecurityManager.class); + private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(Fastjson2SecurityManager.class); - private final static Set warnedClasses = new ConcurrentHashSet<>(1); + private static final Set warnedClasses = new ConcurrentHashSet<>(1); public Fastjson2SecurityManager(FrameworkModel frameworkModel) { SerializeSecurityManager securityManager = frameworkModel.getBeanFactory().getOrRegisterBean(SerializeSecurityManager.class); @@ -65,28 +67,40 @@ public class Fastjson2SecurityManager implements AllowClassNotifyListener { @Override public Class apply(String typeName, Class expectClass, long features) { - switch (status) { - case STRICT: - return super.apply(typeName, expectClass, features); - case WARN: - Class tryLoad = super.apply(typeName, expectClass, features); - if (tryLoad != null) { - return tryLoad; - } - case DISABLED: - Class localClass = loadClassDirectly(typeName); - if (localClass != null) { - if (status == SerializeCheckStatus.WARN && warnedClasses.add(typeName)) { - logger.error("[Serialization Security] Serialized class " + localClass.getName() + " is not in allow list. " + - "Current mode is `WARN`, will allow to deserialize it by default. " + - "Dubbo will set to `STRICT` mode by default in the future. " + - "Please add it into security/serialize.allowlist or follow FAQ to configure it."); - } - return localClass; - } - default: - return null; + Class tryLoad = super.apply(typeName, expectClass, features); + + // 1. in allow list, return + if (tryLoad != null) { + return tryLoad; } + + // 2. check if in strict mode + if (status == STRICT) { + String msg = "[Serialization Security] Serialized class " + typeName + " is not in allow list. " + + "Current mode is `STRICT`, will disallow to deserialize it by default. " + + "Please add it into security/serialize.allowlist or follow FAQ to configure it."; + if (warnedClasses.add(typeName)) { + logger.error(PROTOCOL_UNTRUSTED_SERIALIZE_CLASS, "", "", msg); + } + + return null; + } + + // 3. try load + Class localClass = loadClassDirectly(typeName); + if (localClass != null) { + if (status == SerializeCheckStatus.WARN && warnedClasses.add(typeName)) { + logger.error(PROTOCOL_UNTRUSTED_SERIALIZE_CLASS, "", "", + "[Serialization Security] Serialized class " + localClass.getName() + " is not in allow list. " + + "Current mode is `WARN`, will allow to deserialize it by default. " + + "Dubbo will set to `STRICT` mode by default in the future. " + + "Please add it into security/serialize.allowlist or follow FAQ to configure it."); + } + return localClass; + } + + // 4. class not found + return null; } public Class loadClassDirectly(String typeName) { diff --git a/dubbo-serialization/dubbo-serialization-hessian2/src/main/java/org/apache/dubbo/common/serialize/hessian2/Hessian2AllowClassManager.java b/dubbo-serialization/dubbo-serialization-hessian2/src/main/java/org/apache/dubbo/common/serialize/hessian2/Hessian2AllowClassManager.java index 906b5878df..a0564d4f66 100644 --- a/dubbo-serialization/dubbo-serialization-hessian2/src/main/java/org/apache/dubbo/common/serialize/hessian2/Hessian2AllowClassManager.java +++ b/dubbo-serialization/dubbo-serialization-hessian2/src/main/java/org/apache/dubbo/common/serialize/hessian2/Hessian2AllowClassManager.java @@ -16,7 +16,10 @@ */ package org.apache.dubbo.common.serialize.hessian2; -import org.apache.dubbo.common.logger.Logger; +import java.util.Arrays; +import java.util.Set; + +import org.apache.dubbo.common.logger.ErrorTypeAwareLogger; import org.apache.dubbo.common.logger.LoggerFactory; import org.apache.dubbo.common.utils.AllowClassNotifyListener; import org.apache.dubbo.common.utils.ConcurrentHashSet; @@ -24,8 +27,7 @@ import org.apache.dubbo.common.utils.SerializeCheckStatus; import org.apache.dubbo.common.utils.SerializeSecurityManager; import org.apache.dubbo.rpc.model.FrameworkModel; -import java.util.Arrays; -import java.util.Set; +import static org.apache.dubbo.common.constants.LoggerCodeConstants.PROTOCOL_UNTRUSTED_SERIALIZE_CLASS; /** * Inspired by Fastjson2 @@ -34,9 +36,9 @@ import java.util.Set; public class Hessian2AllowClassManager implements AllowClassNotifyListener { private static final long MAGIC_HASH_CODE = 0xcbf29ce484222325L; private static final long MAGIC_PRIME = 0x100000001b3L; - private static final Logger logger = LoggerFactory.getLogger(Hessian2AllowClassManager.class); + private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(Hessian2AllowClassManager.class); private volatile SerializeCheckStatus checkStatus = AllowClassNotifyListener.DEFAULT_STATUS; - private final static Set warnedClasses = new ConcurrentHashSet<>(1); + private static final Set warnedClasses = new ConcurrentHashSet<>(1); private volatile long[] allowPrefixes = new long[0]; public Hessian2AllowClassManager(FrameworkModel frameworkModel) { @@ -99,14 +101,15 @@ public class Hessian2AllowClassManager implements AllowClassNotifyListener { "Current mode is `STRICT`, will disallow to deserialize it by default. " + "Please add it into security/serialize.allowlist or follow FAQ to configure it."; if (warnedClasses.add(className)) { - logger.error(msg); + logger.error(PROTOCOL_UNTRUSTED_SERIALIZE_CLASS, "", "", msg); } throw new IllegalArgumentException(msg); } else { Class clazz = Class.forName(className, false, classLoader); if (warnedClasses.add(className)) { - logger.error("[Serialization Security] Serialized class " + clazz.getName() + " is not in allow list. " + + logger.error(PROTOCOL_UNTRUSTED_SERIALIZE_CLASS, "", "", + "[Serialization Security] Serialized class " + clazz.getName() + " is not in allow list. " + "Current mode is `WARN`, will allow to deserialize it by default. " + "Dubbo will set to `STRICT` mode by default in the future. " + "Please add it into security/serialize.allowlist or follow FAQ to configure it.");