新增准则:用户输入口令时对口令域进行掩饰,通常,用户输入的每一个字符都应该以“*”形式回显

wuhaoyang
Guo XIn 8 months ago
parent cf37c3e79b
commit fdedbfa265
  1. 87
      sonar-keyware-plugins-cxx/src/main/java/com/keyware/sonar/cxx/rules/checkers/UserInputPasswordChecker.java
  2. 35
      sonar-keyware-plugins-cxx/src/test/java/com/keyware/sonar/cxx/rules/checkers/UserInputPasswordCheckerTest.java
  3. 49
      sonar-keyware-plugins-cxx/src/test/resources/com/keyware/sonar/cxx/rules/checkers/UserInputPasswordChecker.cc

@ -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<Grammar> {
private static final Map<String, AstNode> 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));
}
}

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

@ -0,0 +1,49 @@
#include <QApplication>
#include <QFormLayout>
#include <QLineEdit>
#include <QPushButton>
#include <QMessageBox>
#include <QDialog>
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();
}
Loading…
Cancel
Save