Add serializable check for pojo (#11431)

This commit is contained in:
Albumen Kevin 2023-02-01 14:03:03 +08:00 committed by GitHub
parent 5c895d4995
commit ce3b0e285a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 93 additions and 52 deletions

View File

@ -16,12 +16,6 @@
*/
package org.apache.dubbo.common.beanutil;
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;
import java.lang.reflect.Field;
@ -32,6 +26,12 @@ import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.Map;
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;
public final class JavaBeanSerializeUtil {
private static final Logger logger = LoggerFactory.getLogger(JavaBeanSerializeUtil.class);
@ -466,7 +466,9 @@ public final class JavaBeanSerializeUtil {
name = name.substring(1, name.length() - 1);
}
SerializeClassChecker.getInstance().validateClass(name);
return Class.forName(name, false, loader);
Class<?> aClass = Class.forName(name, false, loader);
SerializeClassChecker.getInstance().validateClass(aClass);
return aClass;
}
private static boolean isArray(String type) {

View File

@ -17,13 +17,13 @@
package org.apache.dubbo.common.constants;
import org.apache.dubbo.common.URL;
import java.net.NetworkInterface;
import java.util.Properties;
import java.util.concurrent.ExecutorService;
import java.util.regex.Pattern;
import org.apache.dubbo.common.URL;
public interface CommonConstants {
String DUBBO = "dubbo";
@ -412,6 +412,8 @@ public interface CommonConstants {
String CLASS_DESERIALIZE_BLOCKED_LIST = "dubbo.security.serialize.blockedClassList";
String CLASS_DESERIALIZE_CHECK_SERIALIZABLE = "dubbo.application.check-serializable";
String ENABLE_NATIVE_JAVA_GENERIC_SERIALIZE = "dubbo.security.serialize.generic.native-java-enable";
String SERIALIZE_BLOCKED_LIST_FILE_PATH = "security/serialize.blockedlist";

View File

@ -16,11 +16,6 @@
*/
package org.apache.dubbo.common.utils;
import org.apache.dubbo.common.config.ConfigurationUtils;
import org.apache.dubbo.common.constants.CommonConstants;
import org.apache.dubbo.common.logger.Logger;
import org.apache.dubbo.common.logger.LoggerFactory;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
@ -55,6 +50,11 @@ import java.util.concurrent.ConcurrentSkipListMap;
import java.util.function.Consumer;
import java.util.function.Supplier;
import org.apache.dubbo.common.config.ConfigurationUtils;
import org.apache.dubbo.common.constants.CommonConstants;
import org.apache.dubbo.common.logger.Logger;
import org.apache.dubbo.common.logger.LoggerFactory;
import static org.apache.dubbo.common.utils.ClassUtils.isAssignableFrom;
/**
@ -410,6 +410,7 @@ public class PojoUtils {
CLASS_NOT_FOUND_CACHE.put((String) className, NOT_FOUND_VALUE);
}
}
SerializeClassChecker.getInstance().validateClass(type);
}
// special logic for enum

View File

@ -16,16 +16,19 @@
*/
package org.apache.dubbo.common.utils;
import org.apache.dubbo.common.beanutil.JavaBeanSerializeUtil;
import org.apache.dubbo.common.logger.Logger;
import org.apache.dubbo.common.logger.LoggerFactory;
import java.io.IOException;
import java.io.Serializable;
import java.util.Arrays;
import java.util.Locale;
import java.util.Set;
import java.util.concurrent.atomic.AtomicLong;
import org.apache.dubbo.common.beanutil.JavaBeanSerializeUtil;
import org.apache.dubbo.common.config.ConfigurationUtils;
import org.apache.dubbo.common.constants.CommonConstants;
import org.apache.dubbo.common.logger.Logger;
import org.apache.dubbo.common.logger.LoggerFactory;
import static org.apache.dubbo.common.constants.CommonConstants.CLASS_DESERIALIZE_ALLOWED_LIST;
import static org.apache.dubbo.common.constants.CommonConstants.CLASS_DESERIALIZE_BLOCKED_LIST;
import static org.apache.dubbo.common.constants.CommonConstants.CLASS_DESERIALIZE_BLOCK_ALL;
@ -44,6 +47,8 @@ public class SerializeClassChecker {
private final LFUCache<String, Object> CLASS_ALLOW_LFU_CACHE = new LFUCache<>();
private final LFUCache<String, Object> CLASS_BLOCK_LFU_CACHE = new LFUCache<>();
private final boolean checkSerializable;
private final AtomicLong counter = new AtomicLong(0);
private SerializeClassChecker() {
@ -83,6 +88,7 @@ public class SerializeClassChecker {
CLASS_DESERIALIZE_BLOCKED_SET.addAll(Arrays.asList(classStrings));
}
checkSerializable = Boolean.parseBoolean(ConfigurationUtils.getProperty(CommonConstants.CLASS_DESERIALIZE_CHECK_SERIALIZABLE, "true"));
}
public static SerializeClassChecker getInstance() {
@ -137,6 +143,12 @@ public class SerializeClassChecker {
CLASS_ALLOW_LFU_CACHE.put(name, CACHE);
}
public void validateClass(Class<?> aClass) {
if (checkSerializable && !Serializable.class.isAssignableFrom(aClass)) {
error(aClass.getName());
}
}
private void error(String name) {
String notice = "Trigger the safety barrier! " +
"Catch not allowed serialize class. " +

View File

@ -1,12 +1,13 @@
package org.apache.dubbo.common.beanutil;
import java.io.Serializable;
import java.util.Collection;
import java.util.Date;
import java.util.Map;
import org.apache.dubbo.rpc.model.person.FullAddress;
import org.apache.dubbo.rpc.model.person.PersonStatus;
import org.apache.dubbo.rpc.model.person.Phone;
import java.util.Collection;
import java.util.Date;
import java.util.Map;
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
@ -23,7 +24,7 @@ import java.util.Map;
* See the License for the specific language governing permissions and
* limitations under the License.
*/
public class Bean {
public class Bean implements Serializable {
private Class<?> type;

View File

@ -16,9 +16,10 @@
*/
package org.apache.dubbo.common.model;
import java.io.Serializable;
import java.util.Arrays;
public class Person {
public class Person implements Serializable {
byte oneByte = 123;
private String name = "name1";
private int age = 11;

View File

@ -17,12 +17,13 @@
package org.apache.dubbo.common.model;
import java.io.Serializable;
import java.util.Objects;
/**
* this class has no nullary constructor and some field is primitive
*/
public class User {
public class User implements Serializable {
private int age;
private String name;

View File

@ -16,19 +16,7 @@
*/
package org.apache.dubbo.common.utils;
import org.apache.dubbo.common.model.Person;
import org.apache.dubbo.common.model.SerializablePerson;
import org.apache.dubbo.common.model.User;
import org.apache.dubbo.common.model.person.BigPerson;
import org.apache.dubbo.common.model.person.FullAddress;
import org.apache.dubbo.common.model.person.PersonInfo;
import org.apache.dubbo.common.model.person.PersonStatus;
import org.apache.dubbo.common.model.person.Phone;
import com.alibaba.fastjson.JSONObject;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import java.io.Serializable;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.text.SimpleDateFormat;
@ -43,6 +31,19 @@ import java.util.List;
import java.util.Map;
import java.util.UUID;
import org.apache.dubbo.common.model.Person;
import org.apache.dubbo.common.model.SerializablePerson;
import org.apache.dubbo.common.model.User;
import org.apache.dubbo.common.model.person.BigPerson;
import org.apache.dubbo.common.model.person.FullAddress;
import org.apache.dubbo.common.model.person.PersonInfo;
import org.apache.dubbo.common.model.person.PersonStatus;
import org.apache.dubbo.common.model.person.Phone;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import com.alibaba.fastjson.JSONObject;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
@ -764,7 +765,7 @@ public class PojoUtilsTest {
SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY
}
public static class BasicTestData {
public static class BasicTestData implements Serializable {
public boolean a;
public char b;
@ -836,7 +837,7 @@ public class PojoUtilsTest {
}
public static class Parent {
public static class Parent implements Serializable {
public String gender;
public String email;
String name;
@ -881,7 +882,7 @@ public class PojoUtilsTest {
}
}
public static class Child {
public static class Child implements Serializable {
public String gender;
public int age;
String toy;
@ -921,7 +922,7 @@ public class PojoUtilsTest {
}
}
public static class TestData {
public static class TestData implements Serializable {
private Map<String, Child> children = new HashMap<String, Child>();
private List<Child> list = new ArrayList<Child>();
@ -950,7 +951,7 @@ public class PojoUtilsTest {
}
}
public static class InnerPojo<T> {
public static class InnerPojo<T> implements Serializable {
private List<T> list;
public List<T> getList() {
@ -962,7 +963,7 @@ public class PojoUtilsTest {
}
}
public static class ListResult<T> {
public static class ListResult<T> implements Serializable {
List<T> result;
public List<T> getResult() {

View File

@ -16,19 +16,19 @@
*/
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.AfterAll;
import org.junit.jupiter.api.Test;
import java.net.Socket;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import org.apache.dubbo.common.constants.CommonConstants;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import javassist.compiler.Javac;
public class SerializeClassCheckerTest {
@BeforeEach
@ -62,6 +62,26 @@ public class SerializeClassCheckerTest {
});
}
@Test
public void testSerializable1() {
SerializeClassChecker serializeClassChecker = SerializeClassChecker.getInstance();
Assertions.assertThrows(IllegalArgumentException.class, ()-> serializeClassChecker.validateClass(List.class));
}
@Test
public void testSerializable2() {
System.setProperty(CommonConstants.CLASS_DESERIALIZE_CHECK_SERIALIZABLE, "false");
SerializeClassChecker serializeClassChecker = SerializeClassChecker.getInstance();
try {
serializeClassChecker.validateClass(List.class);
} catch (Throwable t) {
Assertions.fail(t);
}
System.clearProperty(CommonConstants.CLASS_DESERIALIZE_CHECK_SERIALIZABLE);
}
@Test
public void testAddAllow() {
System.setProperty(CommonConstants.CLASS_DESERIALIZE_ALLOWED_LIST, Socket.class.getName() + "," + Javac.class.getName());