diff --git a/sonar-keyware-plugins-java/src/main/java/com/keyware/sonar/java/rules/checkers/UserStatusVerifyChecker.java b/sonar-keyware-plugins-java/src/main/java/com/keyware/sonar/java/rules/checkers/UserStatusVerifyChecker.java new file mode 100644 index 0000000..40e953a --- /dev/null +++ b/sonar-keyware-plugins-java/src/main/java/com/keyware/sonar/java/rules/checkers/UserStatusVerifyChecker.java @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2023 - 2024. KeyWare.Co.Ltd All rights reserved. + * 项目名称:信息安全性设计准则检查插件 + * 项目描述:用于检查源代码的安全性设计准则的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.declaration.VariableTreeImpl; +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.List; + +/** + * 对用户进行身份鉴别并建立一个新的会话时让原来的会话失效 + * + * @author RenFengJiang + * @date 2024/1/24 + */ +@Rule(key = "UserStatusVerifyChecker") +public class UserStatusVerifyChecker extends IssuableSubscriptionVisitor { + @Override + public List nodesToVisit() { + return List.of(Tree.Kind.METHOD); + } + + @Override + public void visitNode(Tree tree) { + //将Tree强转成MethodTree + MethodTree methodTree = (MethodTree) tree; + //判断是否是doFilter或doFilter方法 + boolean boo = verifyMethod(methodTree); + if(boo){ + //内部实现类 + VisitMethod visitMethod = new VisitMethod(this); + //调用内部实现类 + methodTree.block().accept(visitMethod); + //判断是否满足4个条件 + if(visitMethod.booOne && visitMethod.booTwo && visitMethod.booThree && visitMethod.booFour){ + + }else{ + context.reportIssue(this, methodTree.simpleName(), "对用户进行身份鉴别并建立一个新的会话时让原来的会话失效"); + } + + }else { + context.reportIssue(this, methodTree.simpleName(), "对用户进行身份鉴别并建立一个新的会话时让原来的会话失效"); + } + } + + public static boolean verifyMethod(MethodTree methodTree) { + //判断是否是doFilter或doFilter方法 + if ("doFilter".equals(methodTree.simpleName().name()) || "doFilter".equals(methodTree.simpleName().name())) { + //获取参数 + List parameters = methodTree.parameters(); + for (VariableTree variable : parameters) { + if (variable instanceof VariableTreeImpl) { + //判断参数是否有ServletRequest + VariableTreeImpl variableTree = (VariableTreeImpl) variable; + if (variableTree.type().toString().endsWith("ServletRequest")) { + return true; + } + } + } + } + return false; + } + + static class VisitMethod extends BaseTreeVisitor { + private final UserStatusVerifyChecker checker; + + private boolean booOne = false; + private boolean booTwo = false; + private boolean booThree = false; + private boolean booFour = false; + + + public VisitMethod(UserStatusVerifyChecker checker) { + this.checker = checker; + } + + //方法调用节点 + @Override + public void visitMethodInvocation(MethodInvocationTree tree) { + ExpressionTree expressionTree = tree.methodSelect(); + if(expressionTree instanceof MemberSelectExpressionTreeImpl){ + //判断是否调用指定的方法 + MemberSelectExpressionTreeImpl selectExpressionTree = (MemberSelectExpressionTreeImpl) expressionTree; + if("getParameter".equals(selectExpressionTree.identifier().name()) || "getSession".equals(selectExpressionTree.identifier().name())){ + //获取到调用方法的参数 + Arguments arguments = tree.arguments(); + //调用判断参数的方法 + verifyParam(arguments); + }else if ("invalidate".equals(selectExpressionTree.identifier().name())){ + booFour = true; + } + } + } + + public void verifyParam(Arguments arguments){ + if(arguments instanceof ArgumentListTreeImpl){ + for (ExpressionTree argument : (ArgumentListTreeImpl) arguments) { + if(argument instanceof LiteralTreeImpl){ + LiteralTreeImpl literalTree = (LiteralTreeImpl) argument; + String strName = literalTree.token().text().replace("\"", "").toLowerCase(); + if("username".equals(strName)){ + booOne = true; + }else if("password".equals(strName)){ + booTwo = true; + }else if("false".equals(strName)){ + booThree = true; + } + } + } + } + } + + } +} diff --git a/sonar-keyware-plugins-java/src/main/resources/org/sonar/l10n/java/rules/java/UserStatusVerifyChecker.html b/sonar-keyware-plugins-java/src/main/resources/org/sonar/l10n/java/rules/java/UserStatusVerifyChecker.html new file mode 100644 index 0000000..9fbb8fb --- /dev/null +++ b/sonar-keyware-plugins-java/src/main/resources/org/sonar/l10n/java/rules/java/UserStatusVerifyChecker.html @@ -0,0 +1,16 @@ + + +

对用户进行身份鉴别并建立一个新的会话时让原来的会话失效

+

对用户进行身份鉴别并建立一个新的会话时让原来的会话失效

+
+
+
+

合规解决方案

+
+
+
\ No newline at end of file diff --git a/sonar-keyware-plugins-java/src/main/resources/org/sonar/l10n/java/rules/java/UserStatusVerifyChecker.json b/sonar-keyware-plugins-java/src/main/resources/org/sonar/l10n/java/rules/java/UserStatusVerifyChecker.json new file mode 100644 index 0000000..a0b1bb0 --- /dev/null +++ b/sonar-keyware-plugins-java/src/main/resources/org/sonar/l10n/java/rules/java/UserStatusVerifyChecker.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/UserStatusVerifyChecker.java b/sonar-keyware-plugins-java/src/test/files/UserStatusVerifyChecker.java new file mode 100644 index 0000000..df914f4 --- /dev/null +++ b/sonar-keyware-plugins-java/src/test/files/UserStatusVerifyChecker.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2023 - 2024. KeyWare.Co.Ltd All rights reserved. + * 项目名称:信息安全性设计准则检查插件 + * 项目描述:用于检查源代码的安全性设计准则的Sonarqube插件 + * 版权说明:本软件属北京关键科技股份有限公司所有,在未获得北京关键科技股份有限公司正式授权情况下,任何企业和个人,不能获取、阅读、安装、传播本软件涉及的任何受知识产权保护的内容。 + */ + +import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; + +import javax.servlet.*; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; +import java.io.IOException; + +public class ExampleServlet { + private static final long serialVersionUID = 1391640560504378168L; + + public class AuthenticationFilter implements Filter { + public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {// Noncompliant {{对用户进行身份鉴别并建立一个新的会话时让原来的会话失效}} +// HttpServletRequest request = (HttpServletRequest) req; +// boolean isValidUser = false; +// String username = request.getParameter("username"); +// String password = request.getParameter("password"); +// // 这里应通过相关业务逻辑来验证用户名和密码的准确性 + isValidUser = UserService.validate(username, password); + if (isValidUser) { + HttpSession oldSession = request.getSession(false); + if (oldSession != null) { + oldSession.invalidate(); + } + HttpSession newSession = request.getSession(true); + newSession.setMaxInactiveInterval(30 * 60); + newSession.setAttribute("username", username); + chain.doFilter(req, resp); // 继续执行下一个过滤器或请求 + } else { + request.getRequestDispatcher("/login.jsp").forward(request, resp); // 跳转到登录页面 + } + } + } + + public class AuthenticationInterceptor extends HandlerInterceptorAdapter { + @Override + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {// Noncompliant {{对用户进行身份鉴别并建立一个新的会话时让原来的会话失效}} + boolean isValidUser = false; + String username = request.getParameter("username"); + String password = request.getParameter("password"); + isValidUser = UserService.validate(username, password); + if (isValidUser) { + HttpSession oldSession = request.getSession(false); + if (oldSession != null) { +// oldSession.invalidate(); + } + HttpSession newSession = request.getSession(true); + newSession.setMaxInactiveInterval(30 * 60); + newSession.setAttribute("username", username); + return true; // 继续下一个拦截器或请求处理器 + } else { + response.sendRedirect("/login.jsp"); // 跳转到登录页面 + return false; + } + } + } +} \ No newline at end of file diff --git a/sonar-keyware-plugins-java/src/test/java/com/keyware/sonar/java/rules/checkers/UserStatusVerifyCheckerTest.java b/sonar-keyware-plugins-java/src/test/java/com/keyware/sonar/java/rules/checkers/UserStatusVerifyCheckerTest.java new file mode 100644 index 0000000..1b02cfe --- /dev/null +++ b/sonar-keyware-plugins-java/src/test/java/com/keyware/sonar/java/rules/checkers/UserStatusVerifyCheckerTest.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2023 - 2024. KeyWare.Co.Ltd All rights reserved. + * 项目名称:信息安全性设计准则检查插件 + * 项目描述:用于检查源代码的安全性设计准则的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; + +/** + * 对用户进行身份鉴别并建立一个新的会话时让原来的会话失效 + * + * @author RenFengJiang + * @date 2024/1/24 + */ +public class UserStatusVerifyCheckerTest { + + @Test + void detected() { + + CheckVerifier.newVerifier() + .onFile("src/test/files/UserStatusVerifyChecker.java") + .withCheck(new UserStatusVerifyChecker()) + .withClassPath(FilesUtils.getClassPath("target/test-jars")) + .verifyIssues(); + } +}