parent
e6fb96d32c
commit
6af21ef2db
@ -0,0 +1,30 @@ |
||||
/* |
||||
* Copyright (c) 2023 - 2024. KeyWare.Co.Ltd All rights reserved. |
||||
* 项目名称:C++ 信息安全性设计准则 |
||||
* 项目描述:用于检查C++源代码的安全性设计准则的Sonarqube插件 |
||||
* 版权说明:本软件属北京关键科技股份有限公司所有,在未获得北京关键科技股份有限公司正式授权情况下,任何企业和个人,不能获取、阅读、安装、传播本软件涉及的任何受知识产权保护的内容。 |
||||
*/ |
||||
|
||||
|
||||
package com.keyware.sonar.cxx; |
||||
|
||||
import org.sonar.api.resources.AbstractLanguage; |
||||
|
||||
import java.lang.module.Configuration; |
||||
|
||||
public final class ConfigurationFileLanguage extends AbstractLanguage { |
||||
|
||||
public static final String NAME = "Configuration"; |
||||
public static final String KEY = "cfg"; |
||||
private final Configuration config; |
||||
|
||||
public ConfigurationFileLanguage (Configuration config) { |
||||
super(KEY, NAME); |
||||
this.config = config; |
||||
} |
||||
|
||||
@Override |
||||
public String[] getFileSuffixes() { |
||||
return new String[] {".yml", ".properties", ".ini",".conf" ,".xml" ,".json"}; |
||||
} |
||||
} |
@ -0,0 +1,265 @@ |
||||
/* |
||||
* Copyright (c) 2023 - 2024. KeyWare.Co.Ltd All rights reserved. |
||||
* 项目名称:C++ 信息安全性设计准则 |
||||
* 项目描述:用于检查C++源代码的安全性设计准则的Sonarqube插件 |
||||
* 版权说明:本软件属北京关键科技股份有限公司所有,在未获得北京关键科技股份有限公司正式授权情况下,任何企业和个人,不能获取、阅读、安装、传播本软件涉及的任何受知识产权保护的内容。 |
||||
*/ |
||||
package com.keyware.sonar.cxx.rules.checkers; |
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode; |
||||
import com.fasterxml.jackson.databind.ObjectMapper; |
||||
import com.sonar.cxx.sslr.api.AstNode; |
||||
import com.sonar.cxx.sslr.api.Grammar; |
||||
import org.sonar.check.Rule; |
||||
import org.sonar.cxx.squidbridge.annotations.ActivatedByDefault; |
||||
import org.sonar.cxx.squidbridge.annotations.SqaleConstantRemediation; |
||||
import org.sonar.cxx.squidbridge.checks.SquidCheck; |
||||
import org.w3c.dom.Document; |
||||
import org.w3c.dom.Element; |
||||
import org.w3c.dom.Node; |
||||
import org.w3c.dom.NodeList; |
||||
import org.yaml.snakeyaml.Yaml; |
||||
|
||||
import javax.annotation.Nullable; |
||||
import javax.xml.parsers.DocumentBuilder; |
||||
import javax.xml.parsers.DocumentBuilderFactory; |
||||
import java.io.*; |
||||
import java.util.Iterator; |
||||
import java.util.Map; |
||||
import java.util.Properties; |
||||
import java.util.Scanner; |
||||
|
||||
/** |
||||
* TODO LogChecker |
||||
* |
||||
* @author WuHaoYang |
||||
* @date 2024/1/19 |
||||
*/ |
||||
@Rule(key = "ConfigurationFileChecker", name = "避免在容易受攻击的地方存储口令", description = "避免在容易受攻击的地方存储口令") |
||||
@ActivatedByDefault |
||||
@SqaleConstantRemediation("5min") |
||||
public class ConfigurationFileChecker extends SquidCheck<Grammar> { |
||||
|
||||
|
||||
@Override |
||||
public void visitFile(@Nullable AstNode astNode) { |
||||
String filename = getContext().getInputFile().filename(); |
||||
|
||||
if (filename.endsWith(".properties")) { |
||||
try { |
||||
File file = new File(getContext().getInputFile().absolutePath()); |
||||
try (Scanner scanner = new Scanner(file)) { |
||||
while (scanner.hasNextLine()) { |
||||
String line = scanner.nextLine(); |
||||
if (line.contains("password")) { |
||||
System.out.println(line); |
||||
getContext().createFileViolation(this, "避免在容易受攻击的地方存储口令"); |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
} catch (FileNotFoundException e) { |
||||
System.out.println("文件未找到: " + e.getMessage()); |
||||
} |
||||
} |
||||
|
||||
if (filename.endsWith(".yml")){ |
||||
// 获取当前输入文件的绝对路径
|
||||
File inputFile = getContext().getInputFile().file(); |
||||
String absolutePath = inputFile.getAbsolutePath(); |
||||
|
||||
// 构建目录路径
|
||||
File dir = new File(absolutePath).getParentFile(); |
||||
|
||||
Yaml yaml = new Yaml(); |
||||
for (File file : dir.listFiles()) { |
||||
if (file.isFile() && file.getName().endsWith(".yml")) { |
||||
try (FileInputStream fis = new FileInputStream(file)) { |
||||
Map<String, Object> obj = yaml.load(fis); |
||||
if (obj != null){ |
||||
String password = searchPassword(obj); |
||||
if (password != null) { |
||||
System.out.println("password="+password); |
||||
getContext().createFileViolation(this, "避免在容易受攻击的地方存储口令"); |
||||
} |
||||
} |
||||
} catch (IOException e) { |
||||
e.printStackTrace(); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
if (filename.endsWith(".ini")){ |
||||
// 获取当前输入文件的绝对路径
|
||||
File inputFile = getContext().getInputFile().file(); |
||||
String absolutePath = inputFile.getAbsolutePath(); |
||||
|
||||
// 构建目录路径
|
||||
File folder = new File(absolutePath).getParentFile(); |
||||
File[] listOfFiles = folder.listFiles(); |
||||
|
||||
for (File file : listOfFiles) { |
||||
if (file.isFile() && file.getName().endsWith(".ini")) { |
||||
Properties properties = new Properties(); |
||||
|
||||
try (FileInputStream fileInput = new FileInputStream(file)) { |
||||
properties.load(fileInput); |
||||
String password = properties.getProperty("password"); |
||||
System.out.println("password=" + password); |
||||
getContext().createFileViolation(this, "避免在容易受攻击的地方存储口令"); |
||||
} catch (IOException e) { |
||||
e.printStackTrace(); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
|
||||
if (filename.endsWith(".xml")){ |
||||
// 获取当前输入文件的绝对路径
|
||||
File inputFile = getContext().getInputFile().file(); |
||||
String absolutePath = inputFile.getAbsolutePath(); |
||||
|
||||
// 构建目录路径
|
||||
File dir = new File(absolutePath).getParentFile(); |
||||
|
||||
FilenameFilter filter = new FilenameFilter() { |
||||
public boolean accept(File dir, String name) { |
||||
return name.endsWith(".xml"); |
||||
} |
||||
}; |
||||
|
||||
String[] children = dir.list(filter); |
||||
if (children == null) { |
||||
System.out.println("目录不存在或不是目录"); |
||||
} else { |
||||
for (int i = 0; i < children.length; i++) { |
||||
String filename1 = children[i]; |
||||
File xmlFile = new File(dir, filename1); |
||||
processXML(xmlFile); |
||||
getContext().createFileViolation(this, "避免在容易受攻击的地方存储口令"); |
||||
} |
||||
} |
||||
} |
||||
|
||||
|
||||
if (filename.endsWith(".json")){ |
||||
try { |
||||
// 获取当前输入文件的绝对路径
|
||||
File inputFile = getContext().getInputFile().file(); |
||||
String absolutePath = inputFile.getAbsolutePath(); |
||||
|
||||
// 构建目录路径
|
||||
File folder = new File(absolutePath).getParentFile(); |
||||
|
||||
File[] listOfFiles = folder.listFiles(); |
||||
|
||||
if (listOfFiles != null) { |
||||
ObjectMapper mapper = new ObjectMapper(); |
||||
for (File file : listOfFiles) { |
||||
if (file.isFile() && file.getName().endsWith(".json")) { |
||||
JsonNode rootNode = mapper.readTree(file); |
||||
extractPassword(rootNode); |
||||
getContext().createFileViolation(this, "避免在容易受攻击的地方存储口令"); |
||||
} |
||||
} |
||||
} |
||||
|
||||
} catch (IOException e) { |
||||
e.printStackTrace(); |
||||
} |
||||
} |
||||
|
||||
|
||||
if (filename.endsWith(".conf")){ |
||||
// 获取当前输入文件的绝对路径
|
||||
File inputFile = getContext().getInputFile().file(); |
||||
String absolutePath = inputFile.getAbsolutePath(); |
||||
|
||||
// 构建目录路径
|
||||
File folder = new File(absolutePath).getParentFile(); |
||||
|
||||
File[] listOfFiles = folder.listFiles((dir, name) -> name.endsWith(".conf")); |
||||
|
||||
for (File file : listOfFiles) { |
||||
if (file.isFile()) { |
||||
Properties prop = new Properties(); |
||||
InputStream input = null; |
||||
|
||||
try { |
||||
input = new FileInputStream(file); |
||||
prop.load(input); |
||||
|
||||
if (prop.containsKey("password")) { |
||||
System.out.println("password="+ prop.getProperty("password")); |
||||
getContext().createFileViolation(this, "避免在容易受攻击的地方存储口令"); |
||||
} |
||||
|
||||
} catch (IOException ex) { |
||||
ex.printStackTrace(); |
||||
} finally { |
||||
if (input != null) { |
||||
try { |
||||
input.close(); |
||||
} catch (IOException e) { |
||||
e.printStackTrace(); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
|
||||
|
||||
public static void extractPassword(JsonNode node) { |
||||
Iterator<String> fieldNames = node.fieldNames(); |
||||
while (fieldNames.hasNext()) { |
||||
String fieldName = fieldNames.next(); |
||||
if (fieldName.equals("password")) { |
||||
System.out.println("Password= " + node.get(fieldName).asText()); |
||||
} |
||||
if (node.get(fieldName).isContainerNode()) { |
||||
extractPassword(node.get(fieldName)); |
||||
} |
||||
} |
||||
} |
||||
|
||||
public static void processXML(File xmlFile) { |
||||
try { |
||||
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance(); |
||||
DocumentBuilder dBuilder = dbFactory.newDocumentBuilder(); |
||||
Document doc = dBuilder.parse(xmlFile); |
||||
doc.getDocumentElement().normalize(); |
||||
|
||||
NodeList nList = doc.getElementsByTagName("password"); |
||||
|
||||
for (int i = 0; i < nList.getLength(); i++) { |
||||
Node nNode = nList.item(i); |
||||
if (nNode.getNodeType() == Node.ELEMENT_NODE) { |
||||
Element eElement = (Element) nNode; |
||||
System.out.println("Password="+ eElement.getTextContent()); |
||||
|
||||
} |
||||
} |
||||
} catch (Exception e) { |
||||
e.printStackTrace(); |
||||
} |
||||
} |
||||
|
||||
private static String searchPassword(Map<String, Object> map) { |
||||
for (String key : map.keySet()) { |
||||
if ("password".equals(key) && map.get(key) instanceof String) { |
||||
return (String) map.get(key); |
||||
} else if (map.get(key) instanceof Map) { |
||||
String password = searchPassword((Map<String, Object>) map.get(key)); |
||||
if (password != null) { |
||||
return password; |
||||
} |
||||
} |
||||
} |
||||
return null; |
||||
} |
||||
} |
@ -0,0 +1,72 @@ |
||||
/* |
||||
* Copyright (c) 2023 - 2024. KeyWare.Co.Ltd All rights reserved. |
||||
* 项目名称:C++ 信息安全性设计准则 |
||||
* 项目描述:用于检查C++源代码的安全性设计准则的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.CheckMessage; |
||||
import org.sonar.cxx.squidbridge.api.SourceFile; |
||||
|
||||
import java.io.File; |
||||
import java.io.FilenameFilter; |
||||
import java.io.IOException; |
||||
import java.util.ArrayList; |
||||
import java.util.List; |
||||
|
||||
/** |
||||
* TODO ConfigurationFileCheckerTest |
||||
* |
||||
* @author WuHaoYang |
||||
* @date 2024/1/19 |
||||
*/ |
||||
public class ConfigurationFileCheckerTest { |
||||
|
||||
@Test |
||||
public void checkDirectory() throws IOException { |
||||
|
||||
|
||||
File folder = new File("src/test/resources/com/keyware/sonar/cxx/rules/checkers/configFile"); // 文件夹路径
|
||||
|
||||
File[] files = folder.listFiles(new FilenameFilter() { |
||||
public boolean accept(File dir, String name) { |
||||
return name.endsWith(".yml") || name.endsWith(".ini") || name.endsWith(".properties") || |
||||
name.endsWith(".xml") || name.endsWith(".json") || name.endsWith(".conf"); |
||||
} |
||||
}); |
||||
|
||||
List<String> problems = new ArrayList<>(); // 存储问题的列表
|
||||
|
||||
for (File file : files) { |
||||
|
||||
try { |
||||
if (file.isFile()) { |
||||
var tester = CxxFileTesterHelper.create("configFile/" + file.getName()); |
||||
System.out.println("配置文件名称:" + file.getName()); |
||||
var checker = new ConfigurationFileChecker(); |
||||
SourceFile sourceFile = CxxAstScanner.scanSingleInputFile(tester.asInputFile(), checker); |
||||
|
||||
for (CheckMessage message : sourceFile.getCheckMessages()) { |
||||
if (message.formatDefaultMessage().equals("避免在容易受攻击的地方存储口令")) { |
||||
problems.add("文件:" + file.getName() + " ,问题:" + message.getDefaultMessage()); |
||||
} |
||||
} |
||||
} |
||||
} catch (Exception e) { |
||||
System.out.println("在处理文件时遇到问题:" + file.getName()); |
||||
e.printStackTrace(); |
||||
} |
||||
} |
||||
|
||||
for (String problem : problems) { |
||||
System.out.println(problem); |
||||
} |
||||
} |
||||
|
||||
|
||||
} |
@ -0,0 +1,3 @@ |
||||
# 这是一个.conf配置文件 |
||||
|
||||
password = yourpassword |
@ -0,0 +1,3 @@ |
||||
[UserCredentials] |
||||
username = exampleUser |
||||
password = examplePassword |
@ -0,0 +1,5 @@ |
||||
{ |
||||
"username": "john_doe", |
||||
"password": "s3cr3tP@ssw0rd", |
||||
"email": "john.doe@example.com" |
||||
} |
@ -0,0 +1,2 @@ |
||||
# ConfigurationFileChecker.properties |
||||
password=abc123 |
@ -0,0 +1,7 @@ |
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
|
||||
<user> |
||||
<username>exampleUser</username> |
||||
<password>examplePassword</password> |
||||
</user> |
||||
|
@ -0,0 +1,3 @@ |
||||
database: |
||||
user: admin |
||||
password: mySecurePassword |
Loading…
Reference in new issue