diff --git a/sonar-keyware-plugins-java/src/main/java/com/keyware/sonar/java/rules/checkers/DynamicLibraryLoadChecker.java b/sonar-keyware-plugins-java/src/main/java/com/keyware/sonar/java/rules/checkers/DynamicLibraryLoadChecker.java new file mode 100644 index 0000000..b1abe56 --- /dev/null +++ b/sonar-keyware-plugins-java/src/main/java/com/keyware/sonar/java/rules/checkers/DynamicLibraryLoadChecker.java @@ -0,0 +1,87 @@ +package com.keyware.sonar.java.rules.checkers; + +import org.sonar.check.Rule; +import org.sonar.java.ast.visitors.SubscriptionVisitor; +import org.sonar.plugins.java.api.tree.*; +import org.springframework.lang.NonNull; + +import java.util.Arrays; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * 在动态加载库前应对输入数据进行验证,确保输入数据仅能用于加载允许加载的代码库。 + * 判断逻辑: 当检测到函数中包含调用System.loadLibrary()方法时,则认为是在加载动态库,然后判断其参数是否由方法入参传递的 + * + * @author GuoXin + * @date 2024/1/10 + */ +@Rule(key = "DynamicLibraryLoadChecker") +public class DynamicLibraryLoadChecker extends SubscriptionVisitor { + + @Override + public List nodesToVisit() { + var nodeType = new Tree.Kind[]{Tree.Kind.METHOD}; + return Arrays.asList(nodeType); + } + + @Override + public void visitNode(@NonNull Tree tree) { + if (tree.is(Tree.Kind.METHOD)) { + MethodTree method = (MethodTree) tree; + var block = method.block(); + if (block != null) { + // 拿到方法入参列表 + var methodNames = method.parameters().stream().map((item) -> item.simpleName().name()).collect(Collectors.toSet()); + // 使用方法体查看器对代码块进行遍历 + block.accept(new MethodBodyVisitor(this, methodNames)); + } + } + } + + /** + * 该内部类用于遍历方法体中的代码块,并检查是否调用了System.loadLibrary()方法,并且方法参数为方法入参 + */ + static class MethodBodyVisitor extends BaseTreeVisitor { + private final DynamicLibraryLoadChecker checker; + private final Set methodParameters; + + /** + * 构造方法 + * + * @param checker 动态库加载检查器 + * @param methodParameters 方法入参集合 + */ + public MethodBodyVisitor(DynamicLibraryLoadChecker checker, Set methodParameters) { + this.checker = checker; + this.methodParameters = methodParameters; + } + + /** + * 遍历方法调用语法树节点 + * + * @param tree 语法树节点 + */ + @Override + public void visitMethodInvocation(MethodInvocationTree tree) { + var methodSelect = tree.methodSelect(); + if (methodSelect instanceof MemberSelectExpressionTree) { + var mset = (MemberSelectExpressionTree) methodSelect; + // 判断是否调用了System.loadLibrary() + if (mset.firstToken() != null && "System".equals(mset.firstToken().text()) && "loadLibrary".equals(mset.identifier().name())) { + // 判断方法调用的参数是否是方法入参,在System.loadLibrary()函数仅接受一个参数 + var exp = tree.arguments().get(0); + if (exp.is(Tree.Kind.IDENTIFIER)) { + var id = (IdentifierTree) exp; + if (methodParameters.contains(id.name())) { + // 报告问题 + checker.context.reportIssue(checker, tree, "在动态加载库前对输入数据进行验证,确保输入数据仅能用于加载允许加载的代码库"); + } + } + } + } + } + } + +} diff --git a/sonar-keyware-plugins-java/src/main/resources/org/sonar/l10n/java/rules/java/DynamicLibraryLoadChecker.html b/sonar-keyware-plugins-java/src/main/resources/org/sonar/l10n/java/rules/java/DynamicLibraryLoadChecker.html new file mode 100644 index 0000000..5e9d5ae --- /dev/null +++ b/sonar-keyware-plugins-java/src/main/resources/org/sonar/l10n/java/rules/java/DynamicLibraryLoadChecker.html @@ -0,0 +1,9 @@ +

在动态加载库前对输入数据进行验证,确保输入数据仅能用于加载允许加载的代码库

+

在动态加载库前对输入数据进行验证,确保输入数据仅能用于加载允许加载的代码库。

+
+
+
+

合规解决方案

+
+
+
diff --git a/sonar-keyware-plugins-java/src/main/resources/org/sonar/l10n/java/rules/java/DynamicLibraryLoadChecker.json b/sonar-keyware-plugins-java/src/main/resources/org/sonar/l10n/java/rules/java/DynamicLibraryLoadChecker.json new file mode 100644 index 0000000..eefc274 --- /dev/null +++ b/sonar-keyware-plugins-java/src/main/resources/org/sonar/l10n/java/rules/java/DynamicLibraryLoadChecker.json @@ -0,0 +1,13 @@ +{ + "title": "在动态加载库前对输入数据进行验证,确保输入数据仅能用于加载允许加载的代码库", + "type": "CODE_SMELL", + "status": "ready", + "remediation": { + "func": "Constant\/Issue", + "constantCost": "5min" + }, + "tags": [ + "28suo" + ], + "defaultSeverity": "Minor" +} \ No newline at end of file diff --git a/sonar-keyware-plugins-java/src/test/files/DynamicLibraryLoadChecker.java b/sonar-keyware-plugins-java/src/test/files/DynamicLibraryLoadChecker.java new file mode 100644 index 0000000..8b30244 --- /dev/null +++ b/sonar-keyware-plugins-java/src/test/files/DynamicLibraryLoadChecker.java @@ -0,0 +1,10 @@ +// 在动态加载库前对输入数据进行验证,确保输入数据仅能用于加载允许加载的代码库 +class DynamicLibraryLoadCheckerExample { + + public void loadLibrary(String libraryName, int number) { + String abc = "bac"; + System.loadLibrary("/path/to/your/library"); + System.loadLibrary(libraryName); // Noncompliant {{在动态加载库前对输入数据进行验证,确保输入数据仅能用于加载允许加载的代码库}} + + } +} \ No newline at end of file diff --git a/sonar-keyware-plugins-java/src/test/java/com/keyware/sonar/java/rules/checkers/DynamicLibraryLoadCheckerTest.java b/sonar-keyware-plugins-java/src/test/java/com/keyware/sonar/java/rules/checkers/DynamicLibraryLoadCheckerTest.java new file mode 100644 index 0000000..5e2eb0e --- /dev/null +++ b/sonar-keyware-plugins-java/src/test/java/com/keyware/sonar/java/rules/checkers/DynamicLibraryLoadCheckerTest.java @@ -0,0 +1,23 @@ +package com.keyware.sonar.java.rules.checkers; + +import com.keyware.sonar.java.utils.FilesUtils; +import org.junit.jupiter.api.Test; +import org.sonar.java.checks.verifier.CheckVerifier; + +/** + * 在动态加载库前对输入数据进行验证 单元测试类 + * + * @author GuoXin + * @date 2024/1/10 + */ +public class DynamicLibraryLoadCheckerTest { + + @Test + public void test() { + CheckVerifier.newVerifier() + .onFile("src/test/files/DynamicLibraryLoadChecker.java") + .withCheck(new DynamicLibraryLoadChecker()) + .withClassPath(FilesUtils.getClassPath("target/test-jars")) + .verifyIssues(); + } +}