From fdedbfa26545378154bad7d429eabfeaedb02162 Mon Sep 17 00:00:00 2001 From: Guo XIn <371864209@qq.com> Date: Sat, 20 Jan 2024 16:01:44 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E5=87=86=E5=88=99=EF=BC=9A?= =?UTF-8?q?=E7=94=A8=E6=88=B7=E8=BE=93=E5=85=A5=E5=8F=A3=E4=BB=A4=E6=97=B6?= =?UTF-8?q?=E5=AF=B9=E5=8F=A3=E4=BB=A4=E5=9F=9F=E8=BF=9B=E8=A1=8C=E6=8E=A9?= =?UTF-8?q?=E9=A5=B0=EF=BC=8C=E9=80=9A=E5=B8=B8=EF=BC=8C=E7=94=A8=E6=88=B7?= =?UTF-8?q?=E8=BE=93=E5=85=A5=E7=9A=84=E6=AF=8F=E4=B8=80=E4=B8=AA=E5=AD=97?= =?UTF-8?q?=E7=AC=A6=E9=83=BD=E5=BA=94=E8=AF=A5=E4=BB=A5=E2=80=9C*?= =?UTF-8?q?=E2=80=9D=E5=BD=A2=E5=BC=8F=E5=9B=9E=E6=98=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../checkers/UserInputPasswordChecker.java | 87 +++++++++++++++++++ .../UserInputPasswordCheckerTest.java | 35 ++++++++ .../checkers/UserInputPasswordChecker.cc | 49 +++++++++++ 3 files changed, 171 insertions(+) create mode 100644 sonar-keyware-plugins-cxx/src/main/java/com/keyware/sonar/cxx/rules/checkers/UserInputPasswordChecker.java create mode 100644 sonar-keyware-plugins-cxx/src/test/java/com/keyware/sonar/cxx/rules/checkers/UserInputPasswordCheckerTest.java create mode 100644 sonar-keyware-plugins-cxx/src/test/resources/com/keyware/sonar/cxx/rules/checkers/UserInputPasswordChecker.cc diff --git a/sonar-keyware-plugins-cxx/src/main/java/com/keyware/sonar/cxx/rules/checkers/UserInputPasswordChecker.java b/sonar-keyware-plugins-cxx/src/main/java/com/keyware/sonar/cxx/rules/checkers/UserInputPasswordChecker.java new file mode 100644 index 0000000..d3ff69b --- /dev/null +++ b/sonar-keyware-plugins-cxx/src/main/java/com/keyware/sonar/cxx/rules/checkers/UserInputPasswordChecker.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2023 - 2024. KeyWare.Co.Ltd All rights reserved. + * 项目名称:信息安全性设计准则检查插件 + * 项目描述:用于检查源代码的安全性设计准则的Sonarqube插件 + * 版权说明:本软件属北京关键科技股份有限公司所有,在未获得北京关键科技股份有限公司正式授权情况下,任何企业和个人,不能获取、阅读、安装、传播本软件涉及的任何受知识产权保护的内容。 + */ + +package com.keyware.sonar.cxx.rules.checkers; + +import com.sonar.cxx.sslr.api.AstNode; +import com.sonar.cxx.sslr.api.Grammar; +import org.sonar.check.Priority; +import org.sonar.check.Rule; +import org.sonar.cxx.parser.CxxGrammarImpl; +import org.sonar.cxx.squidbridge.annotations.ActivatedByDefault; +import org.sonar.cxx.squidbridge.annotations.SqaleConstantRemediation; +import org.sonar.cxx.squidbridge.checks.SquidCheck; + +import javax.annotation.Nullable; +import java.util.HashMap; +import java.util.Map; + +/** + * 规则:用户输入口令时对口令域进行掩饰,通常,用户输入的每一个字符都应该以“*”形式回显 + * 实现逻辑:在Qt中,检验是否使用QLineEdit并将其echoMode属性设置为QLineEdit::Password, 如: + * QLineEdit *passwordLineEdit = new QLineEdit; + * passwordLineEdit->setEchoMode(QLineEdit::Password); + * + * @author GuoXin + * @date 2024/1/20 + */ +@Rule(key = "UserInputPasswordChecker", name = "用户输入口令时应对口令域进行掩饰", description = "用户输入口令时对口令域进行掩饰,通常,用户输入的每一个字符都应该以“*”形式回显", priority = Priority.INFO, tags = {"28suo"}) +@ActivatedByDefault +@SqaleConstantRemediation("5min") +public class UserInputPasswordChecker extends SquidCheck { + private static final Map fieldsMap = new HashMap<>(); + + @Override + public void init() { + subscribeTo(CxxGrammarImpl.simpleDeclaration); + } + + @Override + public void visitNode(AstNode astNode) { + var declNode = astNode.getFirstDescendant(CxxGrammarImpl.declSpecifier); + if (declNode == null) { + return; + } + var declName = declNode.getTokenValue(); + if (!"QLineEdit".equals(declName)) { + return; + } + astNode.getFirstDescendant(CxxGrammarImpl.initDeclaratorList).getChildren().forEach(child -> { + var fieldName = child.getFirstDescendant(CxxGrammarImpl.declaratorId).getTokenValue(); + if (fieldName.toLowerCase().contains("password")) { + fieldsMap.put(fieldName, child); + + // 判断声明节点的下一个节点是否为函数调用节点 + var next = astNode.getNextAstNode(); + do { + if (fieldName.equals(next.getTokenValue())) { + var nnext = next.getNextAstNode(); + if (nnext != null && "setEchoMode".equals(nnext.getTokenValue())) { + var paramNode = nnext.getFirstDescendant(CxxGrammarImpl.parameterDeclarationList); + if (paramNode.hasDescendant(CxxGrammarImpl.qualifiedId)) { + var qualifiedNode = paramNode.getFirstDescendant(CxxGrammarImpl.qualifiedId); + if (qualifiedNode != null) { + if ("QLineEdit".equals(qualifiedNode.getFirstChild().getTokenValue()) + && "Password".equals(qualifiedNode.getLastChild().getTokenValue())) { + fieldsMap.remove(fieldName); + } + } + } + } + } + next = next.getNextAstNode(); + } while (next != null); + } + + }); + } + + @Override + public void leaveFile(@Nullable AstNode astNode) { + fieldsMap.values().forEach(node -> getContext().createLineViolation(this, "用户输入口令时对口令域进行掩饰,通常,用户输入的每一个字符都应该以“*”形式回显", node)); + } +} diff --git a/sonar-keyware-plugins-cxx/src/test/java/com/keyware/sonar/cxx/rules/checkers/UserInputPasswordCheckerTest.java b/sonar-keyware-plugins-cxx/src/test/java/com/keyware/sonar/cxx/rules/checkers/UserInputPasswordCheckerTest.java new file mode 100644 index 0000000..5cb3f71 --- /dev/null +++ b/sonar-keyware-plugins-cxx/src/test/java/com/keyware/sonar/cxx/rules/checkers/UserInputPasswordCheckerTest.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2023 - 2024. KeyWare.Co.Ltd All rights reserved. + * 项目名称:信息安全性设计准则检查插件 + * 项目描述:用于检查源代码的安全性设计准则的Sonarqube插件 + * 版权说明:本软件属北京关键科技股份有限公司所有,在未获得北京关键科技股份有限公司正式授权情况下,任何企业和个人,不能获取、阅读、安装、传播本软件涉及的任何受知识产权保护的内容。 + */ + +package com.keyware.sonar.cxx.rules.checkers; + +import com.keyware.sonar.cxx.CxxFileTesterHelper; +import org.junit.jupiter.api.Test; +import org.sonar.cxx.CxxAstScanner; +import org.sonar.cxx.squidbridge.api.SourceFile; +import org.sonar.cxx.squidbridge.checks.CheckMessagesVerifier; + +import java.io.IOException; + +/** + * 测试规则:用户输入口令时对口令域进行掩饰,通常,用户输入的每一个字符都应该以“*”形式回显 + * + * @author GuoXin + * @date 2024/1/20 + */ +public class UserInputPasswordCheckerTest { + @Test + public void checkTest() throws IOException { + var checker = new UserInputPasswordChecker(); + var tester = CxxFileTesterHelper.create("UserInputPasswordChecker.cc"); + SourceFile file = CxxAstScanner.scanSingleInputFile(tester.asInputFile(), checker); + CheckMessagesVerifier.verify(file.getCheckMessages()) + .next().atLine(18).withMessage("用户输入口令时对口令域进行掩饰,通常,用户输入的每一个字符都应该以“*”形式回显") + .next().atLine(22).withMessage("用户输入口令时对口令域进行掩饰,通常,用户输入的每一个字符都应该以“*”形式回显") + .noMore(); + } +} diff --git a/sonar-keyware-plugins-cxx/src/test/resources/com/keyware/sonar/cxx/rules/checkers/UserInputPasswordChecker.cc b/sonar-keyware-plugins-cxx/src/test/resources/com/keyware/sonar/cxx/rules/checkers/UserInputPasswordChecker.cc new file mode 100644 index 0000000..77e29a7 --- /dev/null +++ b/sonar-keyware-plugins-cxx/src/test/resources/com/keyware/sonar/cxx/rules/checkers/UserInputPasswordChecker.cc @@ -0,0 +1,49 @@ +#include +#include +#include +#include +#include +#include +class LoginDialog : public QDialog +{ +public: + LoginDialog(QWidget *parent = nullptr) + : QDialog(parent) + { + setWindowTitle("注册界面"); + // 设置用户名输入框 + QLineEdit *usernameLineEdit = new QLineEdit; + usernameLineEdit.setPlaceholderText("请输入用户名"); + // 设置密码输入框 + QLineEdit *passwordLineEdit = new QLineEdit; // error 应对口领域进行演示 + //passwordLineEdit->setEchoMode(QLineEdit::Password); + passwordLineEdit->setPlaceholderText("请输入密码"); + // 设置密码输入框 + QLineEdit rePasswordLineEdit = new QLineEdit; // error 应对口领域进行演示 + //rePasswordLineEdit.setEchoMode(QLineEdit::Password); + rePasswordLineEdit.setPlaceholderText("请在次输入密码"); + // 设置登录按钮 + QPushButton *loginButton = new QPushButton("注册"); + connect(loginButton, &QPushButton::clicked, this, [=this]() { + if (usernameLineEdit->text().isEmpty() || passwordLineEdit->text().isEmpty()) { + QMessageBox::warning(this, "警告", "用户名或密码不能为空!"); + } else { + // 在此处验证用户名和密码... + } + }); + // 使用表单布局设置窗口布局 + QFormLayout *formLayout = new QFormLayout; + formLayout->addRow("用户名:", usernameLineEdit); + formLayout->addRow("密码:", passwordLineEdit); + formLayout->addRow("再次输入密码:", passwordLineEdit); + formLayout->addWidget(loginButton); + setLayout(formLayout); + } +}; +int main(int argc, char *argv[]) +{ + QApplication app(argc, argv); + LoginDialog dialog; + dialog.show(); + return app.exec(); +} \ No newline at end of file