diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/DefaultSerializeClassChecker.java b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/DefaultSerializeClassChecker.java index 029f654abd2..de44530ab60 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/DefaultSerializeClassChecker.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/DefaultSerializeClassChecker.java @@ -111,12 +111,19 @@ public Class loadClass(ClassLoader classLoader, String className) throws Clas String msg = "[Serialization Security] Serialized class " + className + " has not implement Serializable interface. " + "Current mode is strict check, will disallow to deserialize it by default. "; - if (serializeSecurityManager.getWarnedClasses().add(className)) { - logger.error(PROTOCOL_UNTRUSTED_SERIALIZE_CLASS, "", "", msg); + if (checkSerializable + && checkStatus != SerializeCheckStatus.WARN + && checkStatus != SerializeCheckStatus.DISABLE) { + if (serializeSecurityManager.getWarnedClasses().add(className)) { + logger.error(PROTOCOL_UNTRUSTED_SERIALIZE_CLASS, "", "", msg); + } + throw new IllegalArgumentException(msg); } - if (checkSerializable) { - throw new IllegalArgumentException(msg); + if (checkStatus == SerializeCheckStatus.WARN) { + if (serializeSecurityManager.getWarnedClasses().add(className)) { + logger.warn(PROTOCOL_UNTRUSTED_SERIALIZE_CLASS, "", "", msg); + } } } @@ -164,13 +171,14 @@ private Class loadClass0(ClassLoader classLoader, String className) throws Cl if (Arrays.binarySearch(disAllowPrefixes, hash) >= 0) { String msg = "[Serialization Security] Serialized class " + className + " is in disallow list. " - + "Current mode is `WARN`, will disallow 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. " + "Please add it into security/serialize.allowlist or follow FAQ to configure it."; if (serializeSecurityManager.getWarnedClasses().add(className)) { logger.warn(PROTOCOL_UNTRUSTED_SERIALIZE_CLASS, "", "", msg); } - throw new IllegalArgumentException(msg); + return classForName(classLoader, className); } } @@ -185,13 +193,14 @@ private Class loadClass0(ClassLoader classLoader, String className) throws Cl if (Arrays.binarySearch(disAllowPrefixes, hash) >= 0) { String msg = "[Serialization Security] Serialized class " + className + " is in disallow list. " - + "Current mode is `WARN`, will disallow 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. " + "Please add it into security/serialize.allowlist or follow FAQ to configure it."; if (serializeSecurityManager.getWarnedClasses().add(className)) { logger.warn(PROTOCOL_UNTRUSTED_SERIALIZE_CLASS, "", "", msg); } - throw new IllegalArgumentException(msg); + return classForName(classLoader, className); } } diff --git a/dubbo-common/src/test/java/org/apache/dubbo/common/utils/DefaultSerializeClassCheckerTest.java b/dubbo-common/src/test/java/org/apache/dubbo/common/utils/DefaultSerializeClassCheckerTest.java index 2851b2c050f..6f318c983ee 100644 --- a/dubbo-common/src/test/java/org/apache/dubbo/common/utils/DefaultSerializeClassCheckerTest.java +++ b/dubbo-common/src/test/java/org/apache/dubbo/common/utils/DefaultSerializeClassCheckerTest.java @@ -58,7 +58,8 @@ void testCommon() throws ClassNotFoundException { defaultSerializeClassChecker.loadClass(Thread.currentThread().getContextClassLoader(), int.class.getName()); } - Assertions.assertThrows(IllegalArgumentException.class, () -> { + // In WARN mode, disallowed classes should be loaded with a warning, not throw + Assertions.assertDoesNotThrow(() -> { defaultSerializeClassChecker.loadClass( Thread.currentThread().getContextClassLoader(), Socket.class.getName()); }); @@ -120,6 +121,50 @@ void testAddBlock() { CommonConstants.DubboProperty.DUBBO_CLASS_DESERIALIZE_BLOCKED_LIST); } + @Test + void testDisallowedClassInWarnModeDoesNotThrow() throws ClassNotFoundException { + SystemPropertyConfigUtils.setSystemProperty( + CommonConstants.DubboProperty.DUBBO_CLASS_DESERIALIZE_BLOCKED_LIST, Runtime.class.getName()); + + SerializeSecurityManager ssm = + FrameworkModel.defaultModel().getBeanFactory().getBean(SerializeSecurityManager.class); + ssm.setCheckStatus(SerializeCheckStatus.WARN); + + DefaultSerializeClassChecker checker = DefaultSerializeClassChecker.getInstance(); + + // WARN mode: disallowed class should be loaded with warning, not throw + Assertions.assertDoesNotThrow(() -> { + checker.loadClass(Thread.currentThread().getContextClassLoader(), Runtime.class.getName()); + }); + Assertions.assertTrue(FrameworkModel.defaultModel() + .getBeanFactory() + .getBean(SerializeSecurityManager.class) + .getWarnedClasses() + .contains(Runtime.class.getName())); + + SystemPropertyConfigUtils.clearSystemProperty( + CommonConstants.DubboProperty.DUBBO_CLASS_DESERIALIZE_BLOCKED_LIST); + } + + @Test + void testDisallowedClassInStrictModeThrows() { + SystemPropertyConfigUtils.setSystemProperty( + CommonConstants.DubboProperty.DUBBO_CLASS_DESERIALIZE_BLOCKED_LIST, Runtime.class.getName()); + + SerializeSecurityManager ssm = + FrameworkModel.defaultModel().getBeanFactory().getBean(SerializeSecurityManager.class); + // Default is STRICT - non-allowed classes should throw + Assertions.assertEquals(SerializeCheckStatus.STRICT, AllowClassNotifyListener.DEFAULT_STATUS); + + DefaultSerializeClassChecker checker = DefaultSerializeClassChecker.getInstance(); + Assertions.assertThrows(IllegalArgumentException.class, () -> { + checker.loadClass(Thread.currentThread().getContextClassLoader(), Runtime.class.getName()); + }); + + SystemPropertyConfigUtils.clearSystemProperty( + CommonConstants.DubboProperty.DUBBO_CLASS_DESERIALIZE_BLOCKED_LIST); + } + @Test void testBlockAll() throws ClassNotFoundException { SystemPropertyConfigUtils.setSystemProperty(