Merge remote-tracking branch 'origin/master'

wuhaoyang
renfengshan 11 months ago
commit 5a6996f7cb
  1. 5
      .gitignore
  2. 26
      sonar-keyware-plugins-java/src/main/java/com/keyware/sonar/java/rules/RulesList.java
  3. 87
      sonar-keyware-plugins-java/src/main/java/com/keyware/sonar/java/rules/checkers/DynamicLibraryLoadChecker.java
  4. 93
      sonar-keyware-plugins-java/src/main/java/com/keyware/sonar/java/rules/checkers/SystemFunctionChecker.java
  5. 9
      sonar-keyware-plugins-java/src/main/resources/org/sonar/l10n/java/rules/java/DynamicLibraryLoadChecker.html
  6. 13
      sonar-keyware-plugins-java/src/main/resources/org/sonar/l10n/java/rules/java/DynamicLibraryLoadChecker.json
  7. 9
      sonar-keyware-plugins-java/src/main/resources/org/sonar/l10n/java/rules/java/SystemFunctionChecker.html
  8. 13
      sonar-keyware-plugins-java/src/main/resources/org/sonar/l10n/java/rules/java/SystemFunctionChecker.json
  9. 10
      sonar-keyware-plugins-java/src/test/files/DynamicLibraryLoadChecker.java
  10. 13
      sonar-keyware-plugins-java/src/test/files/SystemFunctionChecker.java
  11. 23
      sonar-keyware-plugins-java/src/test/java/com/keyware/sonar/java/rules/checkers/DynamicLibraryLoadCheckerTest.java
  12. 24
      sonar-keyware-plugins-java/src/test/java/com/keyware/sonar/java/rules/checkers/SystemFunctionCheckerTest.java

5
.gitignore vendored

@ -4,10 +4,7 @@ target/
!**/src/test/**/target/
### IntelliJ IDEA ###
.idea/modules.xml
.idea/jarRepositories.xml
.idea/compiler.xml
.idea/libraries/
.idea/
*.iws
*.iml
*.ipr

@ -6,14 +6,10 @@
*/
package com.keyware.sonar.java.rules;
import com.keyware.sonar.java.rules.checkers.ABCVarNameChecker;
import com.keyware.sonar.java.rules.checkers.AbsolutePathDetectorChecker;
import com.keyware.sonar.java.rules.checkers.DynamicCodeChecker;
import com.keyware.sonar.java.rules.checkers.PathAndKeywordCheck;
import com.keyware.sonar.java.rules.checkers.*;
import org.sonar.plugins.java.api.JavaCheck;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@ -33,28 +29,20 @@ public final class RulesList {
* These rules are going to target MAIN code only
*/
public static List<Class<? extends JavaCheck>> getJavaChecks() {
return Collections.unmodifiableList(Arrays.asList(
return List.of(
ABCVarNameChecker.class,
AbsolutePathDetectorChecker.class,
PathAndKeywordCheck.class,
DynamicCodeChecker.class
/*SpringControllerRequestMappingEntityRule.class,
AvoidAnnotationRule.class,
AvoidBrandInMethodNamesRule.class,
AvoidMethodDeclarationRule.class,
AvoidSuperClassRule.class,
AvoidTreeListRule.class,
MyCustomSubscriptionRule.class,
SecurityAnnotationMandatoryRule.class*/
));
DynamicCodeChecker.class,
SystemFunctionChecker.class,
DynamicLibraryLoadChecker.class
);
}
/**
* These rules are going to target TEST code only
*/
public static List<Class<? extends JavaCheck>> getJavaTestChecks() {
return Collections.unmodifiableList(Arrays.asList(
/*NoIfStatementInTestsRule.class*/
));
return Collections.emptyList();
}
}

@ -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<Tree.Kind> 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<String> methodParameters;
/**
* 构造方法
*
* @param checker 动态库加载检查器
* @param methodParameters 方法入参集合
*/
public MethodBodyVisitor(DynamicLibraryLoadChecker checker, Set<String> 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, "在动态加载库前对输入数据进行验证,确保输入数据仅能用于加载允许加载的代码库");
}
}
}
}
}
}
}

@ -0,0 +1,93 @@
package com.keyware.sonar.java.rules.checkers;/*
*@title SystemFunctionChecker
*@description
*@author Admin
*@version 1.0
*@create 2024/1/11 9:29
*/
import org.sonar.check.Rule;
import org.sonar.java.checks.helpers.ExpressionsHelper;
import org.sonar.plugins.java.api.IssuableSubscriptionVisitor;
import org.sonar.plugins.java.api.semantic.Symbol;
import org.sonar.plugins.java.api.tree.*;
import java.util.*;
/**
* 在构建命令前对输入数据进行白名单机制验证
*
* @author WuHaoYang
* @date 2024/1/10
*/
@Rule(key = "SystemFunctionChecker")
public class SystemFunctionChecker extends IssuableSubscriptionVisitor {
private static final Set<String> SYSTEM_FUNCTION_NAMES = new HashSet<>(Arrays.asList(
"exec",
"getRuntime().exec",
"ProcessBuilder.command"
));
@Override
public List<Tree.Kind> nodesToVisit() {
return Arrays.asList(Tree.Kind.METHOD_INVOCATION, Tree.Kind.NEW_CLASS);
}
@Override
public void visitNode(Tree tree) {
if (tree.is(Tree.Kind.METHOD_INVOCATION)) {
MethodInvocationTree methodInvocationTree = (MethodInvocationTree) tree;
ExpressionTree methodSelect = methodInvocationTree.methodSelect();
if (methodSelect.is(Tree.Kind.MEMBER_SELECT)) {
MemberSelectExpressionTree memberSelect = (MemberSelectExpressionTree) methodSelect;
String methodName = memberSelect.identifier().name();
if (SYSTEM_FUNCTION_NAMES.contains(methodName)) {
checkSystemCommand(methodInvocationTree.arguments(), methodInvocationTree);
}
}
} else if (tree.is(Tree.Kind.NEW_CLASS)) {
NewClassTree newClassTree = (NewClassTree) tree;
String className = newClassTree.symbolType().name();
if (className.equals("ProcessBuilder")) {//判断是否为ProcessBuilder
checkSystemCommand(newClassTree.arguments(), newClassTree);
}
}
}
private void checkSystemCommand(List<ExpressionTree> arguments, Tree tree) {
for (int i = 0; i < arguments.size(); i++) {
ExpressionTree argument = arguments.get(i);
// 获取方法的参数
Tree parentMethod = findEnclosingMethod(tree);
if (parentMethod != null && parentMethod.is(Tree.Kind.METHOD)) {
MethodTree methodTree = (MethodTree) parentMethod;
List<VariableTree> parameters = methodTree.parameters();
// 检查执行系统命令对象的参数是否与方法的入参相等
if (i < parameters.size()) {
String parameterName = parameters.get(i).simpleName().name();
if (argument.is(Tree.Kind.IDENTIFIER) && ((IdentifierTree) argument).name().equals(parameterName)) {
System.out.println("参数"+parameterName);
reportIssue(tree, "在构建命令前对输入数据进行验证");
}
}
}
}
}
public void reportIssue(Tree tree, String message) {
context.reportIssue(this, tree, message);
}
private Tree findEnclosingMethod(Tree tree) {
while (tree != null && !tree.is(Tree.Kind.METHOD)) {
tree = tree.parent();
}
return tree;
}
}

@ -0,0 +1,9 @@
<h2>在动态加载库前对输入数据进行验证,确保输入数据仅能用于加载允许加载的代码库</h2>
<p>在动态加载库前对输入数据进行验证,确保输入数据仅能用于加载允许加载的代码库。</p>
<pre>
</pre>
<h2>合规解决方案</h2>
<pre>
</pre>

@ -0,0 +1,13 @@
{
"title": "在动态加载库前对输入数据进行验证,确保输入数据仅能用于加载允许加载的代码库",
"type": "CODE_SMELL",
"status": "ready",
"remediation": {
"func": "Constant\/Issue",
"constantCost": "5min"
},
"tags": [
"28suo"
],
"defaultSeverity": "Minor"
}

@ -0,0 +1,9 @@
<p>在构建命令前对输入数据进行验证</p>
<h2>在构建命令前对输入数据进行验证</h2>
<pre>
</pre>
<h2>合规解决方案</h2>
<pre>
</pre>

@ -0,0 +1,13 @@
{
"title": "在构建命令前对输入数据进行验证",
"type": "CODE_SMELL",
"status": "ready",
"remediation": {
"func": "Constant\/Issue",
"constantCost": "5min"
},
"tags": [
"28suo"
],
"defaultSeverity": "Minor"
}

@ -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 {{在动态加载库前对输入数据进行验证,确保输入数据仅能用于加载允许加载的代码库}}
}
}

@ -0,0 +1,13 @@
class SystemFunctionChecker{
public void add(String command){
Process process = Runtime.getRuntime().exec(command); // Noncompliant {{在构建命令前对输入数据进行验证}}
}
public void det(String commands){
ProcessBuilder pb = new ProcessBuilder(commands);// Noncompliant {{在构建命令前对输入数据进行验证}}
}
}

@ -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();
}
}

@ -0,0 +1,24 @@
package com.keyware.sonar.java.rules.checkers;/*
*@title SystemFunctionCheckerTest
*@description
*@author Admin
*@version 1.0
*@create 2024/1/11 9:35
*/
import com.keyware.sonar.java.utils.FilesUtils;
import org.junit.jupiter.api.Test;
import org.sonar.java.checks.verifier.CheckVerifier;
public class SystemFunctionCheckerTest {
@Test
public void test(){
CheckVerifier.newVerifier()
.onFile("src/test/files/SystemFunctionChecker.java")
.withCheck(new SystemFunctionChecker())
.withClassPath(FilesUtils.getClassPath("target/test-jars"))
.verifyIssues();
}
}
Loading…
Cancel
Save