优化准则:禁止在容易受攻击的地方明文存储口令密码。如果需要,考虑存储口令的单向加密散列,以替代明文口令存储。(xml,yml,json)

wuhaoyang
wuhaoyang 10 months ago
parent 89eee52523
commit f04961c259
  1. 12
      sonar-keyware-plugins-java/pom.xml
  2. 22
      sonar-keyware-plugins-java/src/main/java/com/keyware/sonar/java/ConfigFileSquidSensor.java
  3. 2
      sonar-keyware-plugins-java/src/main/java/com/keyware/sonar/java/ConfigurationFileLanguage.java
  4. 144
      sonar-keyware-plugins-java/src/main/java/com/keyware/sonar/java/rules/checkers/ConfigurationFileChecker.java
  5. 4
      sonar-keyware-plugins-java/src/test/files/configFile/ConfigurationFileChecker.conf
  6. 2
      sonar-keyware-plugins-java/src/test/files/configFile/ConfigurationFileChecker.ini
  7. 5
      sonar-keyware-plugins-java/src/test/files/configFile/ConfigurationFileChecker.json
  8. 2
      sonar-keyware-plugins-java/src/test/files/configFile/ConfigurationFileChecker.properties
  9. 7
      sonar-keyware-plugins-java/src/test/files/configFile/ConfigurationFileChecker.xml
  10. 3
      sonar-keyware-plugins-java/src/test/files/configFile/ConfigurationFileChecker.yml

@ -98,6 +98,18 @@
<artifactId>sonar-plugin-api-impl</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.16.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
<version>1.28</version>
<scope>compile</scope>
</dependency>
</dependencies>
<build>

@ -14,9 +14,7 @@ import org.sonar.api.batch.rule.Checks;
import org.sonar.api.batch.sensor.Sensor;
import org.sonar.api.batch.sensor.SensorContext;
import org.sonar.api.batch.sensor.SensorDescriptor;
import org.sonar.api.measures.CoreMetrics;
import java.io.IOException;
public class ConfigFileSquidSensor implements Sensor {
private final Checks<ConfigurationFileChecker> checks;
@ -45,25 +43,5 @@ public class ConfigFileSquidSensor implements Sensor {
}
}
private String readFileContents(InputFile javaFile) {
String content;
try {
content = javaFile.contents();
} catch (IOException e) {
System.err.println("Failed to read " + javaFile + " due to " + e.getMessage());
content = "";
}
return content;
}
private void measureLines(SensorContext context, InputFile javaFile, String content) {
int lines = content.split("[\n\r]").length;
context.<Integer>newMeasure()
.forMetric(CoreMetrics.NCLOC)
.on(javaFile)
.withValue(lines)
.save();
}
}

@ -21,7 +21,7 @@ public class ConfigurationFileLanguage extends AbstractLanguage {
public static final String NAME = "Configuration";
public static final String KEY = "cfg";
public static final String FILE_SUFFIXES_KEY = "sonar.disposition.file.suffixes";
public static final String FILE_SUFFIXES_DEFAULT_VALUE = ".properties,.ini,.conf";
public static final String FILE_SUFFIXES_DEFAULT_VALUE = ".properties,.ini,.conf,.xml,.yml,.json";
private final Configuration config;

@ -6,13 +6,24 @@
*/
package com.keyware.sonar.java.rules.checkers;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.sensor.SensorContext;
import org.sonar.api.batch.sensor.issue.NewIssue;
import org.sonar.api.rule.RuleKey;
import org.sonar.check.Rule;
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.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;
@ -36,6 +47,7 @@ public class ConfigurationFileChecker {
if (filename.endsWith(".properties")) {
try {
File file = new File(inputFile.absolutePath());
System.out.println("---------------properties文件路径----------------"+file);
try (Scanner scanner = new Scanner(file)) {
int lineNum = 1;
while (scanner.hasNextLine()) {
@ -144,6 +156,138 @@ public class ConfigurationFileChecker {
lineNum++;
}
}
if (filename.endsWith(".xml")){
// 获取当前输入文件的绝对路径
File file1 = inputFile.file();
File absoluteFile = file1.getAbsoluteFile();
// 构建目录路径
File dir = new File(String.valueOf(absoluteFile)).getParentFile();
System.out.println("---------------xml文件路径----------------"+dir);
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);
}
}
}
if (filename.endsWith(".json")){
try {
// 获取当前输入文件的绝对路径
File file1 = inputFile.file();
File absoluteFile = file1.getAbsoluteFile();
// 构建目录路径
File folder = new File(String.valueOf(absoluteFile)).getParentFile();
System.out.println("---------------json文件路径----------------"+folder);
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);
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
if (filename.endsWith(".yml")){
// 获取当前输入文件的绝对路径
File file1 = inputFile.file();
File absoluteFile = file1.getAbsoluteFile();
// 构建目录路径
File dir = new File(String.valueOf(absoluteFile)).getParentFile();
System.out.println("---------------yml文件路径----------------"+dir);
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);
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
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();
}
}
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));
}
}
}
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;
}
}

@ -1,2 +1,2 @@
# 这是一个conf配置文件
password = yourpassword
# 这是一个.conf配置文件
password = confPassword

@ -1,3 +1,3 @@
[UserCredentials]
username = exampleUser
password = examplePassword
password = iniPassword

@ -0,0 +1,5 @@
{
"username": "john_doe",
"password": "jsonPassword",
"email": "john.doe@example.com"
}

@ -1,2 +1,2 @@
# ConfigurationFileChecker.properties
password=abc123
password=propertiesPassword

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<user>
<username>exampleUser</username>
<password>xmlPassword</password>
</user>
Loading…
Cancel
Save