diff --git a/src/main/java/com/ql/util/express/config/QLExpressRunStrategy.java b/src/main/java/com/ql/util/express/config/QLExpressRunStrategy.java index 2738afa4..c4bcb51e 100644 --- a/src/main/java/com/ql/util/express/config/QLExpressRunStrategy.java +++ b/src/main/java/com/ql/util/express/config/QLExpressRunStrategy.java @@ -1,5 +1,6 @@ package com.ql.util.express.config; +import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.util.HashSet; import java.util.List; @@ -38,17 +39,20 @@ public class QLExpressRunStrategy { /** * 禁止调用不安全的方法 */ - private static boolean forbidInvokeSecurityRiskMethods = false; + private static boolean forbidInvokeSecurityRiskMethods = true; + private static boolean forbidInvokeSecurityRiskConstructors = true; /** * 黑名单控制 */ private static final Set SECURITY_RISK_METHOD_LIST = new HashSet<>(); + private static final Set SECURE_RISK_CONSTRUCTOR_LIST = new HashSet<>(); /** * 白名单控制 */ private static Set SECURE_METHOD_LIST = new HashSet<>(); + private static Set SECURE_CONSTRUCTOR_LIST = new HashSet<>(); /** * 最大申请的数组大小, 默认没有限制 @@ -86,6 +90,10 @@ public class QLExpressRunStrategy { for (Method method : QLExpressRunStrategy.class.getMethods()) { SECURITY_RISK_METHOD_LIST.add(QLExpressRunStrategy.class.getName() + "." + method.getName()); } + addRiskSecureConstructor(java.lang.ProcessBuilder.class); + addRiskSecureConstructor(java.net.Socket.class); + addRiskSecureConstructor(java.awt.Desktop.class); + addRiskSecureConstructor(java.util.PropertyResourceBundle.class); } private QLExpressRunStrategy() { @@ -132,6 +140,14 @@ public static void setForbidInvokeSecurityRiskMethods(boolean forbidInvokeSecuri QLExpressRunStrategy.forbidInvokeSecurityRiskMethods = forbidInvokeSecurityRiskMethods; } + public static boolean isForbidInvokeSecurityRiskConstructors() { + return forbidInvokeSecurityRiskConstructors; + } + + public static void setForbidInvokeSecurityRiskConstructors(boolean forbidInvokeSecurityRiskConstructors) { + QLExpressRunStrategy.forbidInvokeSecurityRiskConstructors = forbidInvokeSecurityRiskConstructors; + } + /** * TODO 未考虑方法重载的场景 * @@ -150,6 +166,14 @@ public static void addSecureMethod(Class clazz, String methodName) { SECURE_METHOD_LIST.add(clazz.getName() + "." + methodName); } + public static void addRiskSecureConstructor(Class clazz){ + SECURE_RISK_CONSTRUCTOR_LIST.add(clazz.getName()); + } + + public static void addSecureConstructor(Class clazz) { + SECURE_CONSTRUCTOR_LIST.add(clazz.getName()); + } + public static void assertSecurityRiskMethod(Method method) throws QLSecurityRiskException { if (!forbidInvokeSecurityRiskMethods || method == null) { return; @@ -169,6 +193,24 @@ public static void assertSecurityRiskMethod(Method method) throws QLSecurityRisk } } + public static void assertSecurityRiskConstructor(Constructor constructor) throws QLSecurityRiskException { + if (!forbidInvokeSecurityRiskConstructors || constructor == null) { + return; + } + String fullConstructorName = constructor.getDeclaringClass().getName(); + if (SECURE_CONSTRUCTOR_LIST != null && !SECURE_CONSTRUCTOR_LIST.isEmpty()) { + // 有白名单配置时则黑名单失效 + if (!SECURE_CONSTRUCTOR_LIST.contains(fullConstructorName)) { + throw new QLSecurityRiskException("使用QLExpress调用了不安全的系统构造函數:" + constructor); + } + return; + } + + if (SECURE_RISK_CONSTRUCTOR_LIST.contains(fullConstructorName)) { + throw new QLSecurityRiskException("使用QLExpress调用了不安全的系统构造函數:" + constructor); + } + } + /** * @param clazz * @return true 表示位于白名单中, false 表示不在白名单中 diff --git a/src/main/java/com/ql/util/express/instruction/op/OperatorNew.java b/src/main/java/com/ql/util/express/instruction/op/OperatorNew.java index 5427162c..9f84e99a 100644 --- a/src/main/java/com/ql/util/express/instruction/op/OperatorNew.java +++ b/src/main/java/com/ql/util/express/instruction/op/OperatorNew.java @@ -61,7 +61,7 @@ public OperateData executeInner(InstructionSetContext parent, ArraySwap list) th s.append(")"); throw new QLException(s.toString()); } - + QLExpressRunStrategy.assertSecurityRiskConstructor(c); tmpObj = c.newInstance(objs); return OperateDataCacheManager.fetchOperateData(tmpObj, obj); } diff --git a/src/test/java/com/ql/util/express/bugfix/InvokeSecurityRiskConstructorsBlackListTest.java b/src/test/java/com/ql/util/express/bugfix/InvokeSecurityRiskConstructorsBlackListTest.java new file mode 100644 index 00000000..eba2b671 --- /dev/null +++ b/src/test/java/com/ql/util/express/bugfix/InvokeSecurityRiskConstructorsBlackListTest.java @@ -0,0 +1,8 @@ +package com.ql.util.express.bugfix; + +/** + * @Author TaoKan + * @Date 2024/3/12 1:48 PM + */ +public class InvokeSecurityRiskConstructorsBlackListTest { +} diff --git a/src/test/java/com/ql/util/express/bugfix/InvokeSecurityRiskConstructorsTest.java b/src/test/java/com/ql/util/express/bugfix/InvokeSecurityRiskConstructorsTest.java new file mode 100644 index 00000000..74c1453f --- /dev/null +++ b/src/test/java/com/ql/util/express/bugfix/InvokeSecurityRiskConstructorsTest.java @@ -0,0 +1,96 @@ +package com.ql.util.express.bugfix; + +import com.ql.util.express.DefaultContext; +import com.ql.util.express.ExpressRunner; +import com.ql.util.express.config.QLExpressRunStrategy; +import com.ql.util.express.example.CustBean; +import com.ql.util.express.exception.QLException; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + + +public class InvokeSecurityRiskConstructorsTest { + public InvokeSecurityRiskConstructorsTest(){ + + } + + @Before + public void before() { + //系统默认阻止的方法黑名单:System.exit(1);Runtime.getRuntime().exec()两个函数 + QLExpressRunStrategy.setForbidInvokeSecurityRiskConstructors(true); + + //白名单 + QLExpressRunStrategy.addSecureConstructor(InvokeSecurityRiskConstructorsTest.class); + QLExpressRunStrategy.addSecureConstructor(CustBean.class); + QLExpressRunStrategy.addSecureConstructor(java.util.Date.class); + QLExpressRunStrategy.addSecureConstructor(java.util.LinkedList.class); + + QLExpressRunStrategy.addRiskSecureConstructor(InvokeSecurityRiskConstructorsBlackListTest.class); + } + + private static final String[] expressList = new String[] { + "import com.ql.util.express.bugfix.InvokeSecurityRiskConstructorsTest;" + + "InvokeSecurityRiskConstructorsTest w = new InvokeSecurityRiskConstructorsTest();return w;" + , "import com.ql.util.express.bugfix.InvokeSecurityRiskMethodsTest;" + + "InvokeSecurityRiskMethodsTest w = new InvokeSecurityRiskMethodsTest();"}; + + @Test + public void testWhiteList() throws Exception { + ExpressRunner expressRunner = new ExpressRunner(); + DefaultContext context = new DefaultContext<>(); + + Object result = expressRunner.execute(expressList[0], context, null, true, false, 1000); + Assert.assertTrue(result instanceof InvokeSecurityRiskConstructorsTest); + + try { + result = expressRunner.execute(expressList[1], context, null, true, false, 1000); + Assert.fail(); + }catch (QLException e) { + //预期内走这里 + Assert.assertEquals(e.getCause().getMessage(), "使用QLExpress调用了不安全的系统构造函數:public com.ql.util.express.bugfix.InvokeSecurityRiskMethodsTest()"); + } + } + + @Test + public void testSystemBlackListAndToWhiteList() throws Exception { + ExpressRunner expressRunner = new ExpressRunner(); + DefaultContext context = new DefaultContext<>(); + String[] expressList = new String[] { + "import java.net.Socket;" + + "return new Socket();"}; + + try { + Object result = expressRunner.execute(expressList[0], context, null, false, false, 1000); + Assert.fail(); + }catch (QLException e) { + //预期内走这里 + Assert.assertEquals(e.getCause().getMessage(), "使用QLExpress调用了不安全的系统构造函數:public java.net.Socket()"); + } + QLExpressRunStrategy.addSecureConstructor(java.net.Socket.class); + + Object result = expressRunner.execute(expressList[0], context, null, true, false, 1000); + Assert.assertTrue(result instanceof java.net.Socket); + } + + @Test + public void testManualBlackList() throws Exception { + ExpressRunner expressRunner = new ExpressRunner(); + DefaultContext context = new DefaultContext<>(); + String[] expressList = new String[] { + "import com.ql.util.express.bugfix.InvokeSecurityRiskConstructorsBlackListTest;" + + "return new InvokeSecurityRiskConstructorsBlackListTest();"}; + + try { + Object result = expressRunner.execute(expressList[0], context, null, false, false, 1000); + Assert.fail(); + }catch (QLException e) { + //预期内走这里 + Assert.assertEquals(e.getCause().getMessage(), "使用QLExpress调用了不安全的系统构造函數:public com.ql.util.express.bugfix.InvokeSecurityRiskConstructorsBlackListTest()"); + } + QLExpressRunStrategy.addSecureConstructor(InvokeSecurityRiskConstructorsBlackListTest.class); + + Object result = expressRunner.execute(expressList[0], context, null, true, false, 1000); + Assert.assertTrue(result instanceof InvokeSecurityRiskConstructorsBlackListTest); + } +}