Merge remote-tracking branch 'origin/master'

wuhaoyang
wuhaoyang 8 months ago
commit ab4ae0f844
  1. 60
      sonar-keyware-plugins-java/src/main/java/com/keyware/sonar/java/rules/checkers/SessionCacheParamsChecker.java
  2. 124
      sonar-keyware-plugins-java/src/main/java/com/keyware/sonar/java/rules/checkers/UserStatusVerifyChecker.java
  3. 16
      sonar-keyware-plugins-java/src/main/resources/org/sonar/l10n/java/rules/java/SessionCacheParamsChecker.html
  4. 13
      sonar-keyware-plugins-java/src/main/resources/org/sonar/l10n/java/rules/java/SessionCacheParamsChecker.json
  5. 16
      sonar-keyware-plugins-java/src/main/resources/org/sonar/l10n/java/rules/java/UserStatusVerifyChecker.html
  6. 13
      sonar-keyware-plugins-java/src/main/resources/org/sonar/l10n/java/rules/java/UserStatusVerifyChecker.json
  7. 27
      sonar-keyware-plugins-java/src/test/files/SessionCacheParamsChecker.java
  8. 64
      sonar-keyware-plugins-java/src/test/files/UserStatusVerifyChecker.java
  9. 29
      sonar-keyware-plugins-java/src/test/java/com/keyware/sonar/java/rules/checkers/SessionCacheParamsCheckerTest.java
  10. 31
      sonar-keyware-plugins-java/src/test/java/com/keyware/sonar/java/rules/checkers/UserStatusVerifyCheckerTest.java

@ -7,7 +7,15 @@
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.LiteralTreeImpl;
import org.sonar.java.model.expression.MemberSelectExpressionTreeImpl;
import org.sonar.plugins.java.api.IssuableSubscriptionVisitor;
import org.sonar.plugins.java.api.semantic.Symbol;
import org.sonar.plugins.java.api.semantic.Type;
import org.sonar.plugins.java.api.tree.Arguments;
import org.sonar.plugins.java.api.tree.ExpressionTree;
import org.sonar.plugins.java.api.tree.MethodInvocationTree;
import org.sonar.plugins.java.api.tree.Tree;
import javax.annotation.Nonnull;
@ -22,11 +30,15 @@ import java.util.List;
*/
@Rule(key = "SessionCacheParamsChecker")
public class SessionCacheParamsChecker extends IssuableSubscriptionVisitor {
//违规集合
private static final List<String> HIDED_PARAMS = List.of(
"id",
"token"
"userid",
"token",
"url",
"userpassword"
);
private static final String requestType = "javax.servlet.http.HttpServletRequest";
@Override
public List<Tree.Kind> nodesToVisit() {
@ -35,8 +47,44 @@ public class SessionCacheParamsChecker extends IssuableSubscriptionVisitor {
@Override
public void visitNode(@Nonnull Tree tree) {
// ((MemberSelectExpressionTree)methodInvocationTree.methodSelect()).expression().symbolType()
MethodInvocationTree methodInvocationTree = (MethodInvocationTree) tree;
Symbol.MethodSymbol methodSymbol = methodInvocationTree.methodSymbol();
if(methodSymbol.isMethodSymbol()) {
//获取参数
ExpressionTree expressionTree = methodInvocationTree.methodSelect();
if(expressionTree instanceof MemberSelectExpressionTreeImpl){
MemberSelectExpressionTreeImpl selectExpressionTree = (MemberSelectExpressionTreeImpl) expressionTree;
//获取参数类型
Type type = selectExpressionTree.expression().symbolType();
if(type != null){
//判断参数类型和调用方法符不符合要求
if(requestType.equals(type.fullyQualifiedName())
&& ("getParameter".equals(methodSymbol.name()) || "getCookies".equals(methodSymbol.name()))) {
//如果是getCookies方法直接抛错
if("getCookies".equals(methodSymbol.name())){
reportIssue(methodInvocationTree, "页面隐藏域字段、Cookie、URL等关键参数不能直接获取,应缓存到服务器端的会话中并通过会话获取");
}else {
//获取参数
Arguments arguments = methodInvocationTree.arguments();
if(arguments instanceof ArgumentListTreeImpl){
for (ExpressionTree argument : (ArgumentListTreeImpl) arguments) {
if(argument instanceof LiteralTreeImpl){
LiteralTreeImpl literalTree = (LiteralTreeImpl) argument;
//获取参数值
String name = literalTree.token().text().replace("\"", "").toLowerCase();
//判断是否是违规项
if(HIDED_PARAMS.contains(name)){
reportIssue(methodInvocationTree, "页面隐藏域字段、Cookie、URL等关键参数不能直接获取,应缓存到服务器端的会话中并通过会话获取");
break;
}
}
}
}
}
}
}
}
}
}
}

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

@ -0,0 +1,16 @@
<!--
~ Copyright (c) 2023 - 2024. KeyWare.Co.Ltd All rights reserved.
~ 项目名称:信息安全性设计准则检查插件
~ 项目描述:用于检查源代码的安全性设计准则的Sonarqube插件
~ 版权说明:本软件属北京关键科技股份有限公司所有,在未获得北京关键科技股份有限公司正式授权情况下,任何企业和个人,不能获取、阅读、安装、传播本软件涉及的任何受知识产权保护的内容。
-->
<p>页面隐藏域字段、Cookie、URL等关键参数不能直接获取,应缓存到服务器端的会话中并通过会话获取</p>
<h2>页面隐藏域字段、Cookie、URL等关键参数不能直接获取,应缓存到服务器端的会话中并通过会话获取</h2>
<pre>
</pre>
<h2>合规解决方案</h2>
<pre>
</pre>

@ -0,0 +1,13 @@
{
"title": "页面隐藏域字段、Cookie、URL等关键参数不能直接获取,应缓存到服务器端的会话中并通过会话获取",
"type": "CODE_SMELL",
"status": "ready",
"remediation": {
"func": "Constant\/Issue",
"constantCost": "5min"
},
"tags": [
"28suo"
],
"defaultSeverity": "Minor"
}

@ -0,0 +1,16 @@
<!--
~ Copyright (c) 2023 - 2024. KeyWare.Co.Ltd All rights reserved.
~ 项目名称:信息安全性设计准则检查插件
~ 项目描述:用于检查源代码的安全性设计准则的Sonarqube插件
~ 版权说明:本软件属北京关键科技股份有限公司所有,在未获得北京关键科技股份有限公司正式授权情况下,任何企业和个人,不能获取、阅读、安装、传播本软件涉及的任何受知识产权保护的内容。
-->
<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"
}

@ -1,22 +1,31 @@
package com.example;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.*;
public class ExampleServlet extends HttpServlet {
private static final long serialVersionUID = 1391640560504378168L;
public void doGet(HttpServletRequest request, HttpServletResponse response) {
// 直接从request获取参数
String param = request.getParameter("userId"); // Noncompliant {{建议将页面隐藏域字段、Cookie、URL等关键参数缓存到服务器端的会话中,并通过会话获取}}
String param = request.getParameter("userId"); // Noncompliant {{页面隐藏域字段、Cookie、URL等关键参数不能直接获取,应缓存到服务器端的会话中并通过会话获取}}
request.getParameter("userpassword");// Noncompliant {{页面隐藏域字段、Cookie、URL等关键参数不能直接获取,应缓存到服务器端的会话中并通过会话获取}}
request.getParameter("token");// Noncompliant {{页面隐藏域字段、Cookie、URL等关键参数不能直接获取,应缓存到服务器端的会话中并通过会话获取}}
request.getParameter("url");// Noncompliant {{页面隐藏域字段、Cookie、URL等关键参数不能直接获取,应缓存到服务器端的会话中并通过会话获取}}
// 直接从request获取Cookies
Cookie[] cookies = request.getCookies();
Cookie[] cookies = request.getCookies();// Noncompliant {{页面隐藏域字段、Cookie、URL等关键参数不能直接获取,应缓存到服务器端的会话中并通过会话获取}}
// 将参数存储到session
HttpSession session = request.getSession();
session.setAttribute("sessionParam", param);
// 其他代码...
}
private void get(HttpServletRequest request, HttpServletResponse response){
@RestController
class TestController{
@GetMapping("/get")
public void get(HttpServletRequest request){
String userId = request.getParameter("userId");// Noncompliant {{页面隐藏域字段、Cookie、URL等关键参数不能直接获取,应缓存到服务器端的会话中并通过会话获取}}
}
}
}

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

@ -0,0 +1,29 @@
/*
* 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;
/**
* TODO SessionCacheParamsCheckerTest
*
* @author RenFengJiang
* @date 2024/1/24
*/
public class SessionCacheParamsCheckerTest {
@Test
public void test() {
CheckVerifier.newVerifier()
.onFile("src/test/files/SessionCacheParamsChecker.java")
.withCheck(new SessionCacheParamsChecker())
.withClassPath(FilesUtils.getClassPath("target/test-jars"))
.verifyIssues();
}
}

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