新增准则:http会话中敏感cooker安全属性校验准则 修改文件上传校验准则

wuhaoyang
RenFengJiang 10 months ago
parent 1952a415a6
commit 66137166f3
  1. 3
      sonar-keyware-plugins-java/src/main/java/com/keyware/sonar/java/rules/RulesList.java
  2. 6
      sonar-keyware-plugins-java/src/main/java/com/keyware/sonar/java/rules/checkers/RedirectUrlChecker.java
  3. 91
      sonar-keyware-plugins-java/src/main/java/com/keyware/sonar/java/rules/checkers/SecurityCookieChecker.java
  4. 68
      sonar-keyware-plugins-java/src/main/java/com/keyware/sonar/java/rules/checkers/UploadFileVerifyChecker.java
  5. 9
      sonar-keyware-plugins-java/src/main/resources/org/sonar/l10n/java/rules/java/SecurityCookieChecker.html
  6. 13
      sonar-keyware-plugins-java/src/main/resources/org/sonar/l10n/java/rules/java/SecurityCookieChecker.json
  7. 2
      sonar-keyware-plugins-java/src/main/resources/org/sonar/l10n/java/rules/java/UploadFileVerifyChecker.html
  8. 2
      sonar-keyware-plugins-java/src/main/resources/org/sonar/l10n/java/rules/java/UploadFileVerifyChecker.json
  9. 20
      sonar-keyware-plugins-java/src/test/files/SecurityCookieRule.java
  10. 6
      sonar-keyware-plugins-java/src/test/files/UploadFileVerifyRule.java
  11. 6
      sonar-keyware-plugins-java/src/test/java/com/keyware/sonar/java/rules/checkers/RedirectUrlCheckerTest.java
  12. 34
      sonar-keyware-plugins-java/src/test/java/com/keyware/sonar/java/rules/checkers/SecurityCookieCheckerTest.java

@ -35,6 +35,9 @@ public final class RulesList {
PathAndKeywordCheck.class, PathAndKeywordCheck.class,
DynamicCodeChecker.class, DynamicCodeChecker.class,
SystemFunctionChecker.class, SystemFunctionChecker.class,
UploadFileVerifyChecker.class,
SecurityCookieChecker.class,
RedirectUrlChecker.class,
DynamicLibraryLoadChecker.class DynamicLibraryLoadChecker.class
); );
} }

@ -1,3 +1,9 @@
/*
* Copyright (c) 2023 - 2024. KeyWare.Co.Ltd All rights reserved.
* 项目名称Java 信息安全性设计准则
* 项目描述用于检查Java源代码的安全性设计准则的Sonarqube插件
* 版权说明本软件属北京关键科技股份有限公司所有在未获得北京关键科技股份有限公司正式授权情况下任何企业和个人不能获取阅读安装传播本软件涉及的任何受知识产权保护的内容
*/
package com.keyware.sonar.java.rules.checkers; package com.keyware.sonar.java.rules.checkers;
import org.sonar.check.Rule; import org.sonar.check.Rule;

@ -0,0 +1,91 @@
/*
* 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.visitors.SubscriptionVisitor;
import org.sonar.plugins.java.api.tree.*;
import java.util.Collections;
import java.util.List;
/**
* TODO SecurityCookieChecker
*
* @author RenFengJiang
* @date 2024/1/10
*/
@Rule(key = "SecurityCookieChecker")
public class SecurityCookieChecker extends SubscriptionVisitor {
@Override
public List<Tree.Kind> nodesToVisit() {
/**
* Tree.Kind.METHOD方法节点
* Tree.Kind.BLOCK方法的代码块节点
* Tree.Kind.METHOD_INVOCATION 方法的调用节点
*/
return Collections.singletonList(Tree.Kind.METHOD);
}
@Override
public void visitNode(Tree tree) {
MethodTree node = (MethodTree) tree;
List<VariableTree> parameters = node.parameters();
// 盘带是否是文件上传类
boolean boo = parameters.stream().anyMatch(type -> "HttpServletResponse".equals(type.type().toString()));
if(boo){
var bodyVisitor = new MethodBOdyVisitor(this);
node.block().accept(bodyVisitor);
if(bodyVisitor.booHttp){
if(!(bodyVisitor.booAge && bodyVisitor.booCure)){
context.reportIssue(this,node.simpleName(),"设置HTTPS会话中cookie的安全属性");
}
}else {
}
}
}
static class MethodBOdyVisitor extends BaseTreeVisitor{
private final SecurityCookieChecker checker;
// 判断是否是https请求
private boolean booCure = false;
// 设置cooker时长
private boolean booAge = false;
// 设置访问
private boolean booHttp = false;
public MethodBOdyVisitor(SecurityCookieChecker checker ){
this.checker = checker;
}
@Override
public void visitMethodInvocation(MethodInvocationTree tree) {
ExpressionTree expressionTree = tree.methodSelect();
System.out.println(expressionTree);
if(expressionTree instanceof MemberSelectExpressionTree){
MemberSelectExpressionTree memberSelectExpressionTree = (MemberSelectExpressionTree) expressionTree;
switch (memberSelectExpressionTree.identifier().name()){
case "setHttpOnly":
booHttp = true;
break;
case "setSecure":
booCure = true;
break;
case "setMaxAge":
booAge = true;
break;
}
}
}
}
}

@ -22,17 +22,6 @@ import java.util.List;
@Rule(key = "UploadFileVerify") @Rule(key = "UploadFileVerify")
public class UploadFileVerifyChecker extends SubscriptionVisitor { public class UploadFileVerifyChecker extends SubscriptionVisitor {
// 文件全名字
private String fileName = "";
// 文件后缀名
private String fileType = "";
// 是否进行if判断
private boolean nodeOne = true;
// 文件大小
private String sizeName = "";
// 判断权限
private boolean privType = true;
@Override @Override
public List<Tree.Kind> nodesToVisit() { public List<Tree.Kind> nodesToVisit() {
/** /**
@ -51,33 +40,39 @@ public class UploadFileVerifyChecker extends SubscriptionVisitor {
boolean boo = parameters.stream().anyMatch(type -> "MultipartFile".equals(type.type().toString())); boolean boo = parameters.stream().anyMatch(type -> "MultipartFile".equals(type.type().toString()));
if(boo){ if(boo){
// 获取文件名称类型判断是否配置文件权限 // 获取文件名称类型判断是否配置文件权限
new InteriorInvoIf().check(tree); var interiorInvoIf = new InteriorInvoIf();
if(fileType != ""){ interiorInvoIf.check(((MethodTree) tree).block());
// 判断是否对文件后缀进行限制 if(interiorInvoIf.fileType != ""){
new NodeIf(fileType).check(tree);
}else if(fileName != ""){
// 判断是否对文件后缀进行限制 // 判断是否对文件后缀进行限制
new NodeIf(fileName).check(tree); NodeIf nodeIf = new NodeIf(interiorInvoIf.fileType);
nodeIf.check(((MethodTree) tree).block());
if (nodeIf.boo){
context.reportIssue(this, node.simpleName(), "程序设计时,应以“白名单”方式限制允许用户上传的文件的类型");
}
}else {
if(interiorInvoIf.fileName != ""){
// 判断是否对文件后缀进行限制
NodeIf nodeIf = new NodeIf(interiorInvoIf.fileName);
nodeIf.check(((MethodTree) tree).block());
if (nodeIf.boo){
context.reportIssue(this, node.simpleName(), "程序设计时,应以“白名单”方式限制允许用户上传的文件的类型");
} }
// 判断是否获取文件名称
if(nodeOne){
// 没有抛出
context.reportIssue(this, node.simpleName(), "没对上传文件进行判断等操作");
}else { }else {
// 有的话设置位true后续还要用 context.reportIssue(this, node.simpleName(), "程序设计时,应以“白名单”方式限制允许用户上传的文件的类型");
nodeOne = true; }
} }
if(sizeName != ""){
if(interiorInvoIf.sizeName != ""){
// 判断是否对文件大小进行限制 // 判断是否对文件大小进行限制
new NodeIf(sizeName).check(tree); NodeIf nodeIf = new NodeIf(interiorInvoIf.sizeName);
nodeIf.check(((MethodTree) tree).block());
if (nodeIf.boo){
context.reportIssue(this, node.simpleName(), "程序设计时,应以“白名单”方式限制允许用户上传的文件的类型");
} }
// 根据是返回结果进行判断是否抛出异常
if(nodeOne){
context.reportIssue(this, node.simpleName(), "没对上传文件进行判断等操作");
} }
// 判断是否进行权限设置 // 判断是否进行权限设置
if(privType){ if(interiorInvoIf.privType){
context.reportIssue(this, node.simpleName(), "没对上传文件进行判断等操作"); context.reportIssue(this, node.simpleName(), "程序设计时,应以“白名单”方式限制允许用户上传的文件的类型");
} }
} }
@ -85,6 +80,14 @@ public class UploadFileVerifyChecker extends SubscriptionVisitor {
// 內部文件名称类型获取类 // 內部文件名称类型获取类
private class InteriorInvoIf extends SubscriptionVisitor{ private class InteriorInvoIf extends SubscriptionVisitor{
// 文件全名字
public String fileName = "";
// 文件后缀名
public String fileType = "";
// 文件大小
public String sizeName = "";
// 判断权限
public boolean privType = true;
@Override @Override
public List<Tree.Kind> nodesToVisit() { public List<Tree.Kind> nodesToVisit() {
@ -143,6 +146,7 @@ public class UploadFileVerifyChecker extends SubscriptionVisitor {
public class NodeIf extends SubscriptionVisitor{ public class NodeIf extends SubscriptionVisitor{
private String name; private String name;
public boolean boo = true;
@Override @Override
public List<Tree.Kind> nodesToVisit() { public List<Tree.Kind> nodesToVisit() {
return Collections.singletonList(Tree.Kind.IF_STATEMENT); return Collections.singletonList(Tree.Kind.IF_STATEMENT);
@ -163,9 +167,9 @@ public class UploadFileVerifyChecker extends SubscriptionVisitor {
BinaryExpressionTree binaryExpressionTree = (BinaryExpressionTree) condition; BinaryExpressionTree binaryExpressionTree = (BinaryExpressionTree) condition;
// 判断是否进行if判断 // 判断是否进行if判断
if(name.equals(binaryExpressionTree.leftOperand().toString())){ if(name.equals(binaryExpressionTree.leftOperand().toString())){
nodeOne = false; boo = false;
}else if(name.equals(binaryExpressionTree.rightOperand().toString())){ }else if(name.equals(binaryExpressionTree.rightOperand().toString())){
nodeOne = false; boo = false;
} }
} }
} }

@ -0,0 +1,9 @@
<p>设置HTTPS会话中cookie的安全属性</p>
<h2>设置HTTPS会话中的敏感cookie的安全属性</h2>
<pre>
</pre>
<h2>合规解决方案</h2>
<pre>
</pre>

@ -0,0 +1,13 @@
{
"title": "设置HTTPS会话中cookie的安全属性",
"type": "CODE_SMELL",
"status": "ready",
"remediation": {
"func": "Constant\/Issue",
"constantCost": "5min"
},
"tags": [
"28suo"
],
"defaultSeverity": "Minor"
}

@ -1,4 +1,4 @@
<p>上传文件检查</p> <p>程序设计时,应以“白名单”方式限制允许用户上传的文件的类型</p>
<h2>程序设计时,应以“白名单”方式限制允许用户上传的文件的类型(如jpg、png、txt、doc、docx、xls、xlsx、xml等格式)并进行检查,根据业务实际需求,设定上传的文件大小,同时限制文件权限(可读、可写、可执行等)</h2> <h2>程序设计时,应以“白名单”方式限制允许用户上传的文件的类型(如jpg、png、txt、doc、docx、xls、xlsx、xml等格式)并进行检查,根据业务实际需求,设定上传的文件大小,同时限制文件权限(可读、可写、可执行等)</h2>
<pre> <pre>

@ -1,5 +1,5 @@
{ {
"title": "上传文件检查", "title": "程序设计时,应以“白名单”方式限制允许用户上传的文件的类型",
"type": "CODE_SMELL", "type": "CODE_SMELL",
"status": "ready", "status": "ready",
"remediation": { "remediation": {

@ -0,0 +1,20 @@
import javax.servlet.http.HttpServletResponse;
public class SecurityCookieRule {
public void setCookie(HttpServletResponse response) { // Noncompliant {{设置HTTPS会话中cookie的安全属性}}
// 创建一个新的Cookie
Cookie cookie = new Cookie("cookieName", "cookieValue");
// 设置HttpOnly属性(防止通过JavaScript访问)
cookie.setHttpOnly(true);
// 设置Secure属性(表示该Cookie只能通过HTTPS连接传输)
cookie.setSecure(true);
// 设置其他属性,比如过期时间等
// cookie.setMaxAge(3600); // 有效期为1小时
// 将Cookie添加到HTTP响应头中
response.addCookie(cookie);
}
}

@ -10,7 +10,7 @@ public class UploadFileVerifyRule {
private String fileUploadPath; private String fileUploadPath;
@PostMapping("/upload") @PostMapping("/upload")
public Result upload(@RequestParam MultipartFile file) throws IOException { // Noncompliant {{没对上传文件进行判断等操作}} public Result upload(@RequestParam MultipartFile file) throws IOException { // Noncompliant {{程序设计时,应以“白名单”方式限制允许用户上传的文件的类型}}
file.setExecutable(true); file.setExecutable(true);
file.setReadable(true); file.setReadable(true);
@ -24,7 +24,9 @@ public class UploadFileVerifyRule {
//获取文件原始名称 //获取文件原始名称
String originalFilename = file.getOriginalFilename(); String originalFilename = file.getOriginalFilename();
String type = FileUtil.extName(originalFilename); String type = FileUtil.extName(originalFilename);
// if(type == ""){
//
// }
return Result.success(""); return Result.success("");
} }
} }

@ -1,3 +1,9 @@
/*
* Copyright (c) 2023 - 2024. KeyWare.Co.Ltd All rights reserved.
* 项目名称Java 信息安全性设计准则
* 项目描述用于检查Java源代码的安全性设计准则的Sonarqube插件
* 版权说明本软件属北京关键科技股份有限公司所有在未获得北京关键科技股份有限公司正式授权情况下任何企业和个人不能获取阅读安装传播本软件涉及的任何受知识产权保护的内容
*/
package com.keyware.sonar.java.rules.checkers; package com.keyware.sonar.java.rules.checkers;
import com.keyware.sonar.java.utils.FilesUtils; import com.keyware.sonar.java.utils.FilesUtils;

@ -0,0 +1,34 @@
/*
* 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 SecurityCookieCheckerTest
*
* @author RenFengJiang
* @date 2024/1/10
*/
public class SecurityCookieCheckerTest {
@Test
void detected() {
SecurityCookieChecker rule = new SecurityCookieChecker();
// Verifies that the check will raise the adequate issues with the expected message.
// In the test file, lines which should raise an issue have been commented out
// by using the following syntax: "// Noncompliant {{EXPECTED_MESSAGE}}"
CheckVerifier.newVerifier()
.onFile("src/test/files/SecurityCookieRule.java")
.withCheck(rule)
.withClassPath(FilesUtils.getClassPath("target/test-jars"))
.verifyIssues();
}
}
Loading…
Cancel
Save