Merge remote-tracking branch 'origin/master'

wuhaoyang
Guo XIn 8 months ago
commit 297b2cc6db
  1. 97
      sonar-keyware-plugins-java/src/main/java/com/keyware/sonar/java/rules/checkers/HttpInputDataChecker.java
  2. 83
      sonar-keyware-plugins-java/src/main/java/com/keyware/sonar/java/rules/checkers/PasswordRegexCheck.java
  3. 18
      sonar-keyware-plugins-java/src/main/java/com/keyware/sonar/java/rules/checkers/UploadFileVerifyChecker.java
  4. 9
      sonar-keyware-plugins-java/src/main/resources/org/sonar/l10n/java/rules/java/HttpInputDataChecker.html
  5. 13
      sonar-keyware-plugins-java/src/main/resources/org/sonar/l10n/java/rules/java/HttpInputDataChecker.json
  6. 9
      sonar-keyware-plugins-java/src/main/resources/org/sonar/l10n/java/rules/java/PasswordRegexCheck.html
  7. 13
      sonar-keyware-plugins-java/src/main/resources/org/sonar/l10n/java/rules/java/PasswordRegexCheck.json
  8. 25
      sonar-keyware-plugins-java/src/test/files/HttpInputDataRule.java
  9. 16
      sonar-keyware-plugins-java/src/test/files/PasswordRegexCheck.java
  10. 31
      sonar-keyware-plugins-java/src/test/java/com/keyware/sonar/java/rules/checkers/HttpInputDataCheckerTest.java
  11. 31
      sonar-keyware-plugins-java/src/test/java/com/keyware/sonar/java/rules/checkers/PasswordRegexCheckTest.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<Tree.Kind> 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<String> 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;
}
}
}
}
}
}
}
}
}

@ -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<Tree.Kind> 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<ExpressionTree> 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);
}
}

@ -22,6 +22,8 @@ import java.util.List;
@Rule(key = "UploadFileVerify")
public class UploadFileVerifyChecker extends IssuableSubscriptionVisitor {
private final String value = "程序设计时,应以“白名单”方式限制允许用户上传的文件的类型";
@Override
public List<Tree.Kind> 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);
}
}

@ -0,0 +1,9 @@
<p>HTTP输入数据验证</p>
<h2>在写入HTTP响应的报头前对输入数据进行验证或编码,确保输入数据不包含回车换行字符。</h2>
<pre>
</pre>
<h2>合规解决方案</h2>
<pre>
</pre>

@ -0,0 +1,13 @@
{
"title": "HTTP输入数据验证",
"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,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");
// 其他操作...
}
}

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

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

@ -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();
}
}
Loading…
Cancel
Save