Switch default check level (#11279)

This commit is contained in:
Albumen Kevin 2023-01-11 15:01:16 +08:00 committed by GitHub
parent fc00efd704
commit 67993e168e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 66 additions and 43 deletions

View File

@ -291,6 +291,8 @@ public interface LoggerCodeConstants {
String PROTOCOL_FAILED_DECODE = "4-20"; String PROTOCOL_FAILED_DECODE = "4-20";
String PROTOCOL_UNTRUSTED_SERIALIZE_CLASS = "4-21";
// Config module // Config module
String CONFIG_FAILED_CONNECT_REGISTRY = "5-1"; String CONFIG_FAILED_CONNECT_REGISTRY = "5-1";

View File

@ -20,7 +20,7 @@ import java.util.Set;
public interface AllowClassNotifyListener { public interface AllowClassNotifyListener {
SerializeCheckStatus DEFAULT_STATUS = SerializeCheckStatus.STRICT; SerializeCheckStatus DEFAULT_STATUS = SerializeCheckStatus.WARN;
void notify(SerializeCheckStatus status, Set<String> prefixList); void notify(SerializeCheckStatus status, Set<String> prefixList);
} }

View File

@ -16,10 +16,6 @@
*/ */
package org.apache.dubbo.common.utils; 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.io.IOException;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.GenericArrayType; import java.lang.reflect.GenericArrayType;
@ -36,12 +32,18 @@ import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors; 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.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 { public class SerializeSecurityManager {
private final Set<String> allowedPrefix = new LinkedHashSet<>(); private final Set<String> 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(); private final SerializeClassChecker checker = SerializeClassChecker.getInstance();
@ -59,6 +61,7 @@ public class SerializeSecurityManager {
.collect(Collectors.toList()); .collect(Collectors.toList());
for (URL u : urls) { for (URL u : urls) {
try { try {
logger.info("Read serialize allow list from " + u);
String[] lines = IOUtils.readLines(u.openStream()); String[] lines = IOUtils.readLines(u.openStream());
for (String line : lines) { for (String line : lines) {
line = line.trim(); line = line.trim();
@ -68,11 +71,12 @@ public class SerializeSecurityManager {
allowedPrefix.add(line); allowedPrefix.add(line);
} }
} catch (IOException e) { } 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) { } 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();
} }
} }

View File

@ -16,7 +16,11 @@
*/ */
package org.apache.dubbo.common.serialize.fastjson2; 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.logger.LoggerFactory;
import org.apache.dubbo.common.utils.AllowClassNotifyListener; import org.apache.dubbo.common.utils.AllowClassNotifyListener;
import org.apache.dubbo.common.utils.ConcurrentHashSet; 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.filter.Filter;
import com.alibaba.fastjson2.util.TypeUtils; 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 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 { public class Fastjson2SecurityManager implements AllowClassNotifyListener {
private Filter securityFilter = new Handler(AllowClassNotifyListener.DEFAULT_STATUS, new String[0]); 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<String> warnedClasses = new ConcurrentHashSet<>(1); private static final Set<String> warnedClasses = new ConcurrentHashSet<>(1);
public Fastjson2SecurityManager(FrameworkModel frameworkModel) { public Fastjson2SecurityManager(FrameworkModel frameworkModel) {
SerializeSecurityManager securityManager = frameworkModel.getBeanFactory().getOrRegisterBean(SerializeSecurityManager.class); SerializeSecurityManager securityManager = frameworkModel.getBeanFactory().getOrRegisterBean(SerializeSecurityManager.class);
@ -65,28 +67,40 @@ public class Fastjson2SecurityManager implements AllowClassNotifyListener {
@Override @Override
public Class<?> apply(String typeName, Class<?> expectClass, long features) { public Class<?> apply(String typeName, Class<?> expectClass, long features) {
switch (status) { Class<?> tryLoad = super.apply(typeName, expectClass, features);
case STRICT:
return super.apply(typeName, expectClass, features); // 1. in allow list, return
case WARN: if (tryLoad != null) {
Class<?> tryLoad = super.apply(typeName, expectClass, features); return tryLoad;
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;
} }
// 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) { public Class<?> loadClassDirectly(String typeName) {

View File

@ -16,7 +16,10 @@
*/ */
package org.apache.dubbo.common.serialize.hessian2; 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.logger.LoggerFactory;
import org.apache.dubbo.common.utils.AllowClassNotifyListener; import org.apache.dubbo.common.utils.AllowClassNotifyListener;
import org.apache.dubbo.common.utils.ConcurrentHashSet; 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.common.utils.SerializeSecurityManager;
import org.apache.dubbo.rpc.model.FrameworkModel; import org.apache.dubbo.rpc.model.FrameworkModel;
import java.util.Arrays; import static org.apache.dubbo.common.constants.LoggerCodeConstants.PROTOCOL_UNTRUSTED_SERIALIZE_CLASS;
import java.util.Set;
/** /**
* Inspired by Fastjson2 * Inspired by Fastjson2
@ -34,9 +36,9 @@ import java.util.Set;
public class Hessian2AllowClassManager implements AllowClassNotifyListener { public class Hessian2AllowClassManager implements AllowClassNotifyListener {
private static final long MAGIC_HASH_CODE = 0xcbf29ce484222325L; private static final long MAGIC_HASH_CODE = 0xcbf29ce484222325L;
private static final long MAGIC_PRIME = 0x100000001b3L; 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 volatile SerializeCheckStatus checkStatus = AllowClassNotifyListener.DEFAULT_STATUS;
private final static Set<String> warnedClasses = new ConcurrentHashSet<>(1); private static final Set<String> warnedClasses = new ConcurrentHashSet<>(1);
private volatile long[] allowPrefixes = new long[0]; private volatile long[] allowPrefixes = new long[0];
public Hessian2AllowClassManager(FrameworkModel frameworkModel) { public Hessian2AllowClassManager(FrameworkModel frameworkModel) {
@ -99,14 +101,15 @@ public class Hessian2AllowClassManager implements AllowClassNotifyListener {
"Current mode is `STRICT`, will disallow to deserialize it by default. " + "Current mode is `STRICT`, will disallow to deserialize it by default. " +
"Please add it into security/serialize.allowlist or follow FAQ to configure it."; "Please add it into security/serialize.allowlist or follow FAQ to configure it.";
if (warnedClasses.add(className)) { if (warnedClasses.add(className)) {
logger.error(msg); logger.error(PROTOCOL_UNTRUSTED_SERIALIZE_CLASS, "", "", msg);
} }
throw new IllegalArgumentException(msg); throw new IllegalArgumentException(msg);
} else { } else {
Class<?> clazz = Class.forName(className, false, classLoader); Class<?> clazz = Class.forName(className, false, classLoader);
if (warnedClasses.add(className)) { 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. " + "Current mode is `WARN`, will allow to deserialize it by default. " +
"Dubbo will set to `STRICT` mode by default in the future. " + "Dubbo will set to `STRICT` mode by default in the future. " +
"Please add it into security/serialize.allowlist or follow FAQ to configure it."); "Please add it into security/serialize.allowlist or follow FAQ to configure it.");