From 987b77fea9c0f688a6c1205d68fe283edfe7170f Mon Sep 17 00:00:00 2001 From: RenFengJiang <1111> Date: Fri, 12 Jan 2024 19:08:55 +0800 Subject: [PATCH 1/3] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E5=87=86=E5=88=99?= =?UTF-8?q?=EF=BC=9AHTTP=E8=BE=93=E5=85=A5=E6=95=B0=E6=8D=AE=E9=AA=8C?= =?UTF-8?q?=E8=AF=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../rules/checkers/HttpInputDataChecker.java | 97 +++++++++++++++++++ .../java/rules/java/HttpInputDataChecker.html | 9 ++ .../java/rules/java/HttpInputDataChecker.json | 13 +++ .../src/test/files/HttpInputDataRule.java | 25 +++++ .../checkers/HttpInputDataCheckerTest.java | 31 ++++++ 5 files changed, 175 insertions(+) create mode 100644 sonar-keyware-plugins-java/src/main/java/com/keyware/sonar/java/rules/checkers/HttpInputDataChecker.java create mode 100644 sonar-keyware-plugins-java/src/main/resources/org/sonar/l10n/java/rules/java/HttpInputDataChecker.html create mode 100644 sonar-keyware-plugins-java/src/main/resources/org/sonar/l10n/java/rules/java/HttpInputDataChecker.json create mode 100644 sonar-keyware-plugins-java/src/test/files/HttpInputDataRule.java create mode 100644 sonar-keyware-plugins-java/src/test/java/com/keyware/sonar/java/rules/checkers/HttpInputDataCheckerTest.java diff --git a/sonar-keyware-plugins-java/src/main/java/com/keyware/sonar/java/rules/checkers/HttpInputDataChecker.java b/sonar-keyware-plugins-java/src/main/java/com/keyware/sonar/java/rules/checkers/HttpInputDataChecker.java new file mode 100644 index 0000000..4af1927 --- /dev/null +++ b/sonar-keyware-plugins-java/src/main/java/com/keyware/sonar/java/rules/checkers/HttpInputDataChecker.java @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2023 - 2024. KeyWare.Co.Ltd All rights reserved. + * 项目名称:Java 信息安全性设计准则 + * 项目描述:用于检查Java源代码的安全性设计准则的Sonarqube插件 + * 版权说明:本软件属北京关键科技股份有限公司所有,在未获得北京关键科技股份有限公司正式授权情况下,任何企业和个人,不能获取、阅读、安装、传播本软件涉及的任何受知识产权保护的内容。 + */ +package com.keyware.sonar.java.rules.checkers; + +import org.sonar.check.Rule; +import org.sonar.java.ast.parser.ArgumentListTreeImpl; +import org.sonar.java.model.expression.AssignmentExpressionTreeImpl; +import org.sonar.java.model.expression.IdentifierTreeImpl; +import org.sonar.java.model.expression.LiteralTreeImpl; +import org.sonar.java.model.expression.MemberSelectExpressionTreeImpl; +import org.sonar.plugins.java.api.IssuableSubscriptionVisitor; +import org.sonar.plugins.java.api.tree.*; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * TODO HttpInputDataChecker + * + * @author RenFengJiang + * @date 2024/1/12 + */ +@Rule(key = "HttpInputDataChecker") +public class HttpInputDataChecker extends IssuableSubscriptionVisitor { + @Override + public List nodesToVisit() { + /** + * Tree.Kind.METHOD:方法节点 + * Tree.Kind.BLOCK:方法的代码块节点 + * Tree.Kind.METHOD_INVOCATION: 方法的调用节点 + */ + return Collections.singletonList(Tree.Kind.BLOCK); + } + @Override + public void visitNode(Tree tree) { + BlockTree blockTree = (BlockTree) tree; + MethodBodyVisitor methodBodyVisitor = new MethodBodyVisitor(this); + blockTree.accept(methodBodyVisitor); + + } + + static class MethodBodyVisitor extends BaseTreeVisitor{ + private final HttpInputDataChecker checker; + List list = new ArrayList<>(); + MethodBodyVisitor(HttpInputDataChecker checker){ + this.checker = checker; + } + + @Override + public void visitIfStatement(IfStatementTree tree) { + System.out.println(tree); + ExpressionTree condition = tree.condition(); + System.out.println(condition.toString()); + if(condition instanceof AssignmentExpressionTreeImpl){ + AssignmentExpressionTreeImpl assignmentExpressionTree = (AssignmentExpressionTreeImpl) condition; + list.add(assignmentExpressionTree.variable().toString()); + } + } + + @Override + public void visitMethodInvocation(MethodInvocationTree tree) { + ExpressionTree expressionTree = tree.methodSelect(); + if(expressionTree instanceof MemberSelectExpressionTreeImpl){ + MemberSelectExpressionTreeImpl memberSelectExpressionTree = (MemberSelectExpressionTreeImpl) expressionTree; + if("setHeader".equals(memberSelectExpressionTree.identifier().name()) || "addHeader".equals(memberSelectExpressionTree.identifier().name())){ + Arguments arguments = tree.arguments(); + if(arguments instanceof ArgumentListTreeImpl){ + for (ExpressionTree argument : (ArgumentListTreeImpl) arguments) { + if(argument instanceof LiteralTreeImpl){ + LiteralTreeImpl literalTree = (LiteralTreeImpl) argument; + if("STRING_LITERAL".equals(literalTree.kind().name())){ + checker.context.reportIssue(checker, literalTree, "HTTP输入数据验证"); + break; + } + }else if(argument instanceof IdentifierTreeImpl){ + IdentifierTreeImpl identifierTree = (IdentifierTreeImpl) argument; + if(!list.contains(identifierTree.name())){ + checker.context.reportIssue(checker, identifierTree, "HTTP输入数据验证"); + break; + } + } + } + } + } + } + } + + + + + } +} diff --git a/sonar-keyware-plugins-java/src/main/resources/org/sonar/l10n/java/rules/java/HttpInputDataChecker.html b/sonar-keyware-plugins-java/src/main/resources/org/sonar/l10n/java/rules/java/HttpInputDataChecker.html new file mode 100644 index 0000000..e18fed3 --- /dev/null +++ b/sonar-keyware-plugins-java/src/main/resources/org/sonar/l10n/java/rules/java/HttpInputDataChecker.html @@ -0,0 +1,9 @@ +

HTTP输入数据验证

+

在写入HTTP响应的报头前对输入数据进行验证或编码,确保输入数据不包含回车换行字符。

+
+
+
+

合规解决方案

+
+
+
diff --git a/sonar-keyware-plugins-java/src/main/resources/org/sonar/l10n/java/rules/java/HttpInputDataChecker.json b/sonar-keyware-plugins-java/src/main/resources/org/sonar/l10n/java/rules/java/HttpInputDataChecker.json new file mode 100644 index 0000000..2109659 --- /dev/null +++ b/sonar-keyware-plugins-java/src/main/resources/org/sonar/l10n/java/rules/java/HttpInputDataChecker.json @@ -0,0 +1,13 @@ +{ + "title": "HTTP输入数据验证", + "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/HttpInputDataRule.java b/sonar-keyware-plugins-java/src/test/files/HttpInputDataRule.java new file mode 100644 index 0000000..75e50ab --- /dev/null +++ b/sonar-keyware-plugins-java/src/test/files/HttpInputDataRule.java @@ -0,0 +1,25 @@ + +public class HttpInputDataRule { + public static void main(String[] args) { + // 假设有一个HttpServletResponse对象 + HttpServletResponse response = new HttpServletResponse(); + + // 设置单个报头 + response.setHeader("Content-Type", "text/plain"); // Noncompliant {{HTTP输入数据验证}} + + // 添加多个报头 + String a = "Cache-Control"; + String b = "no-cache" ; + if(a = "asds"){ + + } + if(b = "asds"){ + + } + + response.addHeader(a, b); +// response.addHeader("X-Custom-Header", "Custom Value"); + + // 其他操作... + } +} diff --git a/sonar-keyware-plugins-java/src/test/java/com/keyware/sonar/java/rules/checkers/HttpInputDataCheckerTest.java b/sonar-keyware-plugins-java/src/test/java/com/keyware/sonar/java/rules/checkers/HttpInputDataCheckerTest.java new file mode 100644 index 0000000..17e85f1 --- /dev/null +++ b/sonar-keyware-plugins-java/src/test/java/com/keyware/sonar/java/rules/checkers/HttpInputDataCheckerTest.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2023 - 2024. KeyWare.Co.Ltd All rights reserved. + * 项目名称:Java 信息安全性设计准则 + * 项目描述:用于检查Java源代码的安全性设计准则的Sonarqube插件 + * 版权说明:本软件属北京关键科技股份有限公司所有,在未获得北京关键科技股份有限公司正式授权情况下,任何企业和个人,不能获取、阅读、安装、传播本软件涉及的任何受知识产权保护的内容。 + */ +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; + +/** + * TODO HttpInputDataCheckerTest + * + * @author RenFengJiang + * @date 2024/1/12 + */ +public class HttpInputDataCheckerTest { + @Test + void detected() { + HttpInputDataChecker rule = new HttpInputDataChecker(); + + + CheckVerifier.newVerifier() + .onFile("src/test/files/HttpInputDataRule.java") + .withCheck(rule) + .withClassPath(FilesUtils.getClassPath("target/test-jars")) + .verifyIssues(); + } +} From a2eafc5661c07fdc470287bf31aebd5f80119f07 Mon Sep 17 00:00:00 2001 From: RenFengJiang <1111> Date: Fri, 12 Jan 2024 19:09:23 +0800 Subject: [PATCH 2/3] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E5=87=86=E5=88=99?= =?UTF-8?q?=EF=BC=9A=E4=BF=AE=E6=94=B9if=E5=88=A4=E6=96=AD=E6=96=B9?= =?UTF-8?q?=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../checkers/UploadFileVerifyChecker.java | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/sonar-keyware-plugins-java/src/main/java/com/keyware/sonar/java/rules/checkers/UploadFileVerifyChecker.java b/sonar-keyware-plugins-java/src/main/java/com/keyware/sonar/java/rules/checkers/UploadFileVerifyChecker.java index ab34771..46d9c39 100644 --- a/sonar-keyware-plugins-java/src/main/java/com/keyware/sonar/java/rules/checkers/UploadFileVerifyChecker.java +++ b/sonar-keyware-plugins-java/src/main/java/com/keyware/sonar/java/rules/checkers/UploadFileVerifyChecker.java @@ -22,6 +22,8 @@ import java.util.List; @Rule(key = "UploadFileVerify") public class UploadFileVerifyChecker extends IssuableSubscriptionVisitor { + + private final String value = "程序设计时,应以“白名单”方式限制允许用户上传的文件的类型"; @Override public List nodesToVisit() { /** @@ -42,38 +44,38 @@ public class UploadFileVerifyChecker extends IssuableSubscriptionVisitor { //获取文件名称类型判断是否配置文件权限 var interiorInvoIf = new InteriorInvoIf(); ((MethodTree) tree).block().accept(interiorInvoIf); - if (interiorInvoIf.fileType != "") { + if (!interiorInvoIf.fileType.equals("")) { //判断是否对文件后缀进行限制 NodeIf nodeIf = new NodeIf(interiorInvoIf.fileType); ((MethodTree) tree).block().accept(nodeIf); if (nodeIf.boo) { - context.reportIssue(this, node.simpleName(), "程序设计时,应以“白名单”方式限制允许用户上传的文件的类型"); + context.reportIssue(this, node.simpleName(), value); } } else { - if (interiorInvoIf.fileName != "") { + if (!interiorInvoIf.fileName.equals("")) { // 判断是否对文件后缀进行限制 NodeIf nodeIf = new NodeIf(interiorInvoIf.fileName); ((MethodTree) tree).block().accept(nodeIf); if (nodeIf.boo) { - context.reportIssue(this, node.simpleName(), "程序设计时,应以“白名单”方式限制允许用户上传的文件的类型"); + context.reportIssue(this, node.simpleName(), value); } } else { - context.reportIssue(this, node.simpleName(), "程序设计时,应以“白名单”方式限制允许用户上传的文件的类型"); + context.reportIssue(this, node.simpleName(), value); } } - if (interiorInvoIf.sizeName != "") { + if (!interiorInvoIf.sizeName.equals("")) { //判断是否对文件大小进行限制 NodeIf nodeIf = new NodeIf(interiorInvoIf.sizeName); //nodeIf.check(((MethodTree) tree).block()); ((MethodTree) tree).block().accept(nodeIf); if (nodeIf.boo) { - context.reportIssue(this, node.simpleName(), "程序设计时,应以“白名单”方式限制允许用户上传的文件的类型"); + context.reportIssue(this, node.simpleName(), value); } } //判断是否进行权限设置 if (interiorInvoIf.privType) { - context.reportIssue(this, node.simpleName(), "程序设计时,应以“白名单”方式限制允许用户上传的文件的类型"); + context.reportIssue(this, node.simpleName(), value); } } From 4bb5ffd929d321d4f743b1ee3ef58305d91eecd4 Mon Sep 17 00:00:00 2001 From: wuhaoyang <2507865306@qq.com> Date: Sat, 13 Jan 2024 10:10:52 +0800 Subject: [PATCH 3/3] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E5=87=86=E5=88=99?= =?UTF-8?q?=EF=BC=9A=E8=A6=81=E6=B1=82=E7=94=A8=E6=88=B7=E4=BD=BF=E7=94=A8?= =?UTF-8?q?=E5=85=B7=E6=9C=89=E8=B6=B3=E5=A4=9F=E5=A4=8D=E6=9D=82=E5=BA=A6?= =?UTF-8?q?=E7=9A=84=E5=8F=A3=E4=BB=A4.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../rules/checkers/PasswordRegexCheck.java | 83 +++++++++++++++++++ .../java/rules/java/PasswordRegexCheck.html | 9 ++ .../java/rules/java/PasswordRegexCheck.json | 13 +++ .../src/test/files/PasswordRegexCheck.java | 16 ++++ .../checkers/PasswordRegexCheckTest.java | 31 +++++++ 5 files changed, 152 insertions(+) create mode 100644 sonar-keyware-plugins-java/src/main/java/com/keyware/sonar/java/rules/checkers/PasswordRegexCheck.java create mode 100644 sonar-keyware-plugins-java/src/main/resources/org/sonar/l10n/java/rules/java/PasswordRegexCheck.html create mode 100644 sonar-keyware-plugins-java/src/main/resources/org/sonar/l10n/java/rules/java/PasswordRegexCheck.json create mode 100644 sonar-keyware-plugins-java/src/test/files/PasswordRegexCheck.java create mode 100644 sonar-keyware-plugins-java/src/test/java/com/keyware/sonar/java/rules/checkers/PasswordRegexCheckTest.java diff --git a/sonar-keyware-plugins-java/src/main/java/com/keyware/sonar/java/rules/checkers/PasswordRegexCheck.java b/sonar-keyware-plugins-java/src/main/java/com/keyware/sonar/java/rules/checkers/PasswordRegexCheck.java new file mode 100644 index 0000000..dc2374a --- /dev/null +++ b/sonar-keyware-plugins-java/src/main/java/com/keyware/sonar/java/rules/checkers/PasswordRegexCheck.java @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2023 - 2024. KeyWare.Co.Ltd All rights reserved. + * 项目名称:Java 信息安全性设计准则 + * 项目描述:用于检查Java源代码的安全性设计准则的Sonarqube插件 + * 版权说明:本软件属北京关键科技股份有限公司所有,在未获得北京关键科技股份有限公司正式授权情况下,任何企业和个人,不能获取、阅读、安装、传播本软件涉及的任何受知识产权保护的内容。 + */ +package com.keyware.sonar.java.rules.checkers; + + +/** + * 要求用户使用具有足够复杂度的口令。 + * + * @author WuHaoyang + * @date 2024/1/12 + */ +import org.sonar.check.Rule; +import org.sonar.plugins.java.api.IssuableSubscriptionVisitor; +import org.sonar.plugins.java.api.tree.*; + +import java.util.*; + +@Rule(key = "PasswordRegexCheck") +public class PasswordRegexCheck extends IssuableSubscriptionVisitor { + + private static final String MATCHER_METHOD = "matcher"; + private static final String PASSWORD_PARAMETER = "password"; + + @Override + public List nodesToVisit() { + return Collections.singletonList(Tree.Kind.METHOD); + } + + @Override + public void visitNode(Tree tree) { + if (tree.is(Tree.Kind.METHOD)) { + MethodTree methodTree = (MethodTree) tree; + checkPasswordValidation(methodTree); + } + } + + private void checkPasswordValidation(MethodTree methodTree) { + boolean hasPasswordValidation = false; + + for (StatementTree statement : methodTree.block().body()) { + if (statement.is(Tree.Kind.VARIABLE)) { + VariableTree variableTree = (VariableTree) statement; + if (variableTree.initializer() != null && variableTree.initializer().is(Tree.Kind.METHOD_INVOCATION)) { + MethodInvocationTree methodInvocationTree = (MethodInvocationTree) variableTree.initializer(); + String methodName = methodInvocationTree.methodSymbol().name(); + if (MATCHER_METHOD.equals(methodName)) { + hasPasswordValidation = hasPasswordValidation || hasPasswordParameter(methodInvocationTree.arguments()); + } + } + } + } + + if (!hasPasswordValidation) { + //如果没有发现密码验证,报告问题 + System.out.println("未对口令进行复杂度验证"+methodTree.simpleName()); + reportIssue(methodTree.simpleName(), "未对口令进行复杂度验证"); + } + } + + private boolean hasPasswordParameter(List arguments) { + for (ExpressionTree argument : arguments) { + if (argument.is(Tree.Kind.IDENTIFIER)) { + IdentifierTree identifier = (IdentifierTree) argument; + if (PASSWORD_PARAMETER.equalsIgnoreCase(identifier.name())) { + //检查标识符是否有密码验证 + return hasPasswordValidationInMethod(identifier.name()); + } + } + } + + return false; + } + + private boolean hasPasswordValidationInMethod(String paramName) { + //参数名是'password',已经存在 + return PASSWORD_PARAMETER.equalsIgnoreCase(paramName); + } + +} diff --git a/sonar-keyware-plugins-java/src/main/resources/org/sonar/l10n/java/rules/java/PasswordRegexCheck.html b/sonar-keyware-plugins-java/src/main/resources/org/sonar/l10n/java/rules/java/PasswordRegexCheck.html new file mode 100644 index 0000000..97e9b53 --- /dev/null +++ b/sonar-keyware-plugins-java/src/main/resources/org/sonar/l10n/java/rules/java/PasswordRegexCheck.html @@ -0,0 +1,9 @@ +

未对口令进行复杂度验证

+

未对口令进行复杂度验证

+
+
+
+

合规解决方案

+
+
+
diff --git a/sonar-keyware-plugins-java/src/main/resources/org/sonar/l10n/java/rules/java/PasswordRegexCheck.json b/sonar-keyware-plugins-java/src/main/resources/org/sonar/l10n/java/rules/java/PasswordRegexCheck.json new file mode 100644 index 0000000..d2844a7 --- /dev/null +++ b/sonar-keyware-plugins-java/src/main/resources/org/sonar/l10n/java/rules/java/PasswordRegexCheck.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/PasswordRegexCheck.java b/sonar-keyware-plugins-java/src/test/files/PasswordRegexCheck.java new file mode 100644 index 0000000..3e213b5 --- /dev/null +++ b/sonar-keyware-plugins-java/src/test/files/PasswordRegexCheck.java @@ -0,0 +1,16 @@ +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class PasswordStrengthValidator { + + + + public String isValidPassword(String password) {// Noncompliant {{未对口令进行复杂度验证}} + String asdasd = "asdfsdfsdf"; + Pattern pattern = Pattern.compile("^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*[@$!%*#?&])[A-Za-z\\d@$!%*#?&]{8,}$"); + Matcher matcher1 = pattern.matcher(asdasd); + Matcher matcher3 = pattern.matcher(); + return password; + } + +} \ No newline at end of file diff --git a/sonar-keyware-plugins-java/src/test/java/com/keyware/sonar/java/rules/checkers/PasswordRegexCheckTest.java b/sonar-keyware-plugins-java/src/test/java/com/keyware/sonar/java/rules/checkers/PasswordRegexCheckTest.java new file mode 100644 index 0000000..79adc14 --- /dev/null +++ b/sonar-keyware-plugins-java/src/test/java/com/keyware/sonar/java/rules/checkers/PasswordRegexCheckTest.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2023 - 2024. KeyWare.Co.Ltd All rights reserved. + * 项目名称:Java 信息安全性设计准则 + * 项目描述:用于检查Java源代码的安全性设计准则的Sonarqube插件 + * 版权说明:本软件属北京关键科技股份有限公司所有,在未获得北京关键科技股份有限公司正式授权情况下,任何企业和个人,不能获取、阅读、安装、传播本软件涉及的任何受知识产权保护的内容。 + */ +package com.keyware.sonar.java.rules.checkers;/* + *@title PasswordRegexCheckTest + *@description + *@author Admin + *@version 1.0 + *@create 2024/1/12 14:56 + */ + +import com.keyware.sonar.java.utils.FilesUtils; +import org.junit.jupiter.api.Test; +import org.sonar.java.checks.verifier.CheckVerifier; + +public class PasswordRegexCheckTest { + + + @Test + void detected() { + + CheckVerifier.newVerifier() + .onFile("src/test/files/PasswordRegexCheck.java") + .withCheck(new PasswordRegexCheck()) + .withClassPath(FilesUtils.getClassPath("target/test-jars")) + .verifyIssues(); + } +}