parent
aaee78b3fd
commit
c0365cb297
@ -0,0 +1,17 @@ |
||||
/* |
||||
* Copyright (c) 2023 - 2024. KeyWare.Co.Ltd All rights reserved. |
||||
* 项目名称:信息安全性设计准则检查插件 |
||||
* 项目描述:用于检查源代码的安全性设计准则的Sonarqube插件 |
||||
* 版权说明:本软件属北京关键科技股份有限公司所有,在未获得北京关键科技股份有限公司正式授权情况下,任何企业和个人,不能获取、阅读、安装、传播本软件涉及的任何受知识产权保护的内容。 |
||||
*/ |
||||
package com.keyware.sonar.cxx.rules; |
||||
|
||||
/** |
||||
* C++ 安全设计准则检查规则属性 |
||||
* |
||||
* @author GuoXin |
||||
* @date 2024/1/18 |
||||
*/ |
||||
public class SecurityDesignRuleProperties { |
||||
|
||||
} |
@ -0,0 +1,133 @@ |
||||
/* |
||||
* 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.api.utils.log.Logger; |
||||
import org.sonar.api.utils.log.Loggers; |
||||
import org.sonar.check.Priority; |
||||
import org.sonar.check.Rule; |
||||
import org.sonar.cxx.parser.CxxGrammarImpl; |
||||
import org.sonar.cxx.squidbridge.api.CheckMessage; |
||||
import org.sonar.cxx.squidbridge.api.SourceCode; |
||||
import org.sonar.cxx.visitors.MultiLocatitionSquidCheck; |
||||
|
||||
import javax.annotation.Nonnull; |
||||
import java.util.Set; |
||||
|
||||
|
||||
/** |
||||
* 应通过用户名口令、数字证书等其他手段对主机身份进行鉴别 |
||||
* <p>仅检测代码中有没有用户名口令和数字证书</p> |
||||
* |
||||
* @author GuoXin |
||||
* @date 2024/1/24 |
||||
*/ |
||||
@Rule(key = "HostIdentityVerifyChecker", name = "程序中未识别到通过用户名口令或者数字证书验证等安全认证逻辑", description = "应通过用户名口令、数字证书等其他手段对主机身份进行鉴别", priority = Priority.MAJOR, tags = {"28suo"}) |
||||
public class HostIdentityVerifyChecker extends MultiLocatitionSquidCheck<Grammar> { |
||||
private static final Logger LOG = Loggers.get(HostIdentityVerifyChecker.class); |
||||
private SourceCode project; |
||||
|
||||
private boolean hasUsername = false; |
||||
private boolean hasPassword = false; |
||||
private boolean hasCertificate = false; |
||||
|
||||
private final Set<String> SSL_FUNCTIONS = Set.of( |
||||
"SSL_use_certificate_file", |
||||
"SSL_use_PrivateKey_file", |
||||
"SSL_use_RSAPrivateKey_file", |
||||
"SSL_CTX_use_certificate_file", |
||||
"SSL_CTX_use_RSAPrivateKey_file", |
||||
"SSL_CTX_use_PrivateKey_file", |
||||
"SSL_CTX_use_certificate_chain_file", |
||||
"SSL_use_certificate_chain_file", |
||||
"SSL_library_init", |
||||
"PEM_read_X509", |
||||
"d2i_X509_bio", |
||||
"X509_verify", |
||||
"X509_check_issued", |
||||
"X509_get_notBefore", |
||||
"X509_get_notAfter", |
||||
"X509_get_subject_name", |
||||
"X509_get_issuer_name", |
||||
"X509_get_pubkey", |
||||
"X509_STORE_CTX_init", |
||||
"X509_STORE_add_cert", |
||||
"X509_verify_cert" |
||||
); |
||||
|
||||
@Override |
||||
public void init() { |
||||
LOG.info("[KeyWare][C++检查] >> 应通过用户名口令、数字证书等其他手段对主机身份进行鉴别"); |
||||
if (project == null) { |
||||
project = getContext().peekSourceCode(); |
||||
} |
||||
subscribeTo(CxxGrammarImpl.functionDefinition, CxxGrammarImpl.simpleDeclaration, CxxGrammarImpl.postfixExpression); |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public void visitNode(@Nonnull AstNode astNode) { |
||||
if ((hasUsername && hasPassword) || hasCertificate) { |
||||
return; |
||||
} |
||||
|
||||
if (astNode.is(CxxGrammarImpl.functionDefinition)) { |
||||
visitFunctionDefinition(astNode); |
||||
} else if (astNode.is(CxxGrammarImpl.simpleDeclaration)) { |
||||
visitSimpleDeclaration(astNode); |
||||
} else if (astNode.is(CxxGrammarImpl.postfixExpression)) { |
||||
visitPostfixExpression(astNode); |
||||
} |
||||
} |
||||
|
||||
private void visitFunctionDefinition(@Nonnull AstNode astNode) { |
||||
astNode.getDescendants(CxxGrammarImpl.parameterDeclaration).forEach(this::checkDeclarationNode); |
||||
} |
||||
|
||||
private void visitSimpleDeclaration(@Nonnull AstNode astNode) { |
||||
astNode.getDescendants(CxxGrammarImpl.declarator).forEach(this::checkDeclarationNode); |
||||
} |
||||
|
||||
private void visitPostfixExpression(@Nonnull AstNode astNode) { |
||||
var nameNode = astNode.getFirstDescendant(CxxGrammarImpl.declaratorId); |
||||
if (nameNode == null) { |
||||
nameNode = astNode.getFirstDescendant(CxxGrammarImpl.className); |
||||
} |
||||
if (nameNode != null) { |
||||
var nameStr = nameNode.getTokenValue(); |
||||
if (SSL_FUNCTIONS.contains(nameStr)) { |
||||
hasCertificate = true; |
||||
} |
||||
} |
||||
} |
||||
|
||||
private void checkDeclarationNode(@Nonnull AstNode astNode) { |
||||
var paramNode = astNode.getFirstDescendant(CxxGrammarImpl.declaratorId); |
||||
if (paramNode != null) { |
||||
var paramName = paramNode.getTokenValue(); |
||||
paramName = paramName.toLowerCase().replace("-", "").replace("_", ""); |
||||
if ("username".equals(paramName)) { |
||||
hasUsername = true; |
||||
} else if ("password".equals(paramName)) { |
||||
hasPassword = true; |
||||
} |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 当访问器销毁时执行,代表所有文件已经被访问完毕,可以进行最后的处理。 |
||||
*/ |
||||
@Override |
||||
public void destroy() { |
||||
if (!(hasPassword && hasUsername) && !hasCertificate) { |
||||
project.log(new CheckMessage(this, "应通过用户名口令、数字证书等其他手段对主机身份进行鉴别")); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,45 @@ |
||||
/* |
||||
* 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.api.batch.fs.InputFile; |
||||
import org.sonar.cxx.CxxAstScanner; |
||||
import org.sonar.cxx.config.CxxSquidConfiguration; |
||||
import org.sonar.cxx.squidbridge.api.SourceCode; |
||||
import org.sonar.cxx.squidbridge.api.SourceProject; |
||||
import org.sonar.cxx.squidbridge.indexer.QueryByType; |
||||
|
||||
import java.io.IOException; |
||||
import java.util.Collection; |
||||
import java.util.Set; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
|
||||
/** |
||||
* 测试规则:应通过用户名口令、数字证书等其他手段对主机身份进行鉴别 |
||||
* |
||||
* @author GuoXin |
||||
* @date 2024/1/24 |
||||
*/ |
||||
public class HostIdentityVerifyCheckerTest { |
||||
@Test |
||||
public void checkTest() throws IOException { |
||||
var checker = new HostIdentityVerifyChecker(); |
||||
var tester = CxxFileTesterHelper.create("HostIdentityVerifyChecker.cc"); |
||||
var scanner = CxxAstScanner.create(new CxxSquidConfiguration(), checker); |
||||
Set<InputFile> inputFiles = Set.of(tester.asInputFile()); |
||||
scanner.scanInputFiles(inputFiles); |
||||
Collection<SourceCode> squidSourceFiles = scanner.getIndex().search(new QueryByType(SourceProject.class)); |
||||
assertThat(squidSourceFiles).size().isEqualTo(1); |
||||
squidSourceFiles.forEach(sourceCode -> { |
||||
assertThat(sourceCode.getCheckMessages()).size().isEqualTo(1); |
||||
}); |
||||
} |
||||
} |
@ -0,0 +1,80 @@ |
||||
#include <iostream> |
||||
#include <string> |
||||
#include <boost/asio.hpp> |
||||
// 本示例中对合规代码进行了注释
|
||||
|
||||
// 假设有一个函数去异步验证用户名和密码
|
||||
/*void verify_credentials(const std::string& username, const std::string& password) {
|
||||
// 如果验证成功,则执行相应操作
|
||||
if (is_valid(username, password)) { |
||||
std::cout << "Authentication successful." << std::endl; |
||||
} else { |
||||
std::cout << "Invalid credentials." << std::endl; |
||||
} |
||||
}*/ |
||||
|
||||
int main() { |
||||
/*std::string user_name, pass_word;
|
||||
std::cout << "Enter your username: "; |
||||
std::cin >> user_name; |
||||
std::cout << "Enter your password: "; |
||||
std::getline(std::cin, pass_word); |
||||
|
||||
// 调用验证函数
|
||||
verify_credentials(user_name, pass_word);*/ |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
#include <openssl/x509.h> |
||||
#include <openssl/pem.h> |
||||
#include <openssl/ssl.h> |
||||
#include <openssl/err.h> |
||||
|
||||
bool verifyCertificate(const std::string& certPath) { |
||||
// 初始化OpenSSL库
|
||||
/*SSL_library_init();
|
||||
OpenSSL_add_all_algorithms(); |
||||
ERR_load_crypto_strings(); |
||||
|
||||
// 加载证书文件
|
||||
FILE* certFile = fopen(certPath.c_str(), "r"); |
||||
if (!certFile) { |
||||
perror("Failed to open certificate file"); |
||||
return false; |
||||
} |
||||
|
||||
X509* x509Cert = PEM_read_X509(certFile, NULL, NULL, NULL); |
||||
fclose(certFile); |
||||
|
||||
if (!x509Cert) { |
||||
ERR_print_errors_fp(stderr); |
||||
return false; |
||||
} |
||||
|
||||
// 这里只做简单的证书有效性检查,真实场景下需要构建完整的信任链并验证到根CA
|
||||
int result = X509_verify(x509Cert, NULL); |
||||
|
||||
|
||||
// 释放资源
|
||||
X509_free(x509Cert); |
||||
|
||||
// 返回验证结果
|
||||
return (result == 1);*/ |
||||
} |
||||
|
||||
int main2() { |
||||
const std::string certPath = "/path/to/certificate.pem"; |
||||
bool isVerified = verifyCertificate(certPath); |
||||
if (isVerified) { |
||||
std::cout << "The certificate has been verified successfully." << std::endl; |
||||
} else { |
||||
std::cout << "Failed to verify the certificate." << std::endl; |
||||
} |
||||
|
||||
// 清理OpenSSL库
|
||||
EVP_cleanup(); |
||||
ERR_free_strings(); |
||||
|
||||
return 0; |
||||
} |
Loading…
Reference in new issue