parent
0061c15772
commit
3818b0832d
@ -0,0 +1,60 @@ |
||||
/* |
||||
* Copyright (c) 2023 - 2024. KeyWare.Co.Ltd All rights reserved. |
||||
* 项目名称:信息安全性设计准则检查插件 |
||||
* 项目描述:用于检查源代码的安全性设计准则的Sonarqube插件 |
||||
* 版权说明:本软件属北京关键科技股份有限公司所有,在未获得北京关键科技股份有限公司正式授权情况下,任何企业和个人,不能获取、阅读、安装、传播本软件涉及的任何受知识产权保护的内容。 |
||||
*/ |
||||
package com.keyware.sonar.java; |
||||
|
||||
import org.sonar.api.config.Configuration; |
||||
import org.sonar.api.config.PropertyDefinition; |
||||
import org.sonar.api.resources.AbstractLanguage; |
||||
import org.sonar.api.resources.Qualifiers; |
||||
|
||||
import java.util.Arrays; |
||||
import java.util.List; |
||||
|
||||
import static java.util.Arrays.asList; |
||||
|
||||
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"; |
||||
|
||||
private final Configuration config; |
||||
|
||||
public ConfigurationFileLanguage(Configuration config) { |
||||
super(KEY, NAME); |
||||
this.config = config; |
||||
} |
||||
|
||||
@Override |
||||
public String[] getFileSuffixes() { |
||||
String[] suffixes = config.getStringArray(FILE_SUFFIXES_KEY); |
||||
|
||||
if (suffixes == null || suffixes.length == 0) { |
||||
return FILE_SUFFIXES_DEFAULT_VALUE.split(","); |
||||
} |
||||
|
||||
// 修剪空格和小写后缀
|
||||
return Arrays.stream(suffixes) |
||||
.map(String::trim) |
||||
.map(String::toLowerCase) |
||||
.toArray(String[]::new); |
||||
} |
||||
|
||||
public static List<PropertyDefinition> getProperties() { |
||||
return asList( |
||||
PropertyDefinition.builder(FILE_SUFFIXES_KEY) |
||||
.multiValues(true) |
||||
.defaultValue(FILE_SUFFIXES_DEFAULT_VALUE) |
||||
.category("FileType") |
||||
.name("File Suffixes") |
||||
.description("List of suffixes for files to analyze.") |
||||
.onQualifiers(Qualifiers.PROJECT) |
||||
.build() |
||||
); |
||||
} |
||||
} |
@ -0,0 +1,149 @@ |
||||
/* |
||||
* Copyright (c) 2023 - 2024. KeyWare.Co.Ltd All rights reserved. |
||||
* 项目名称:信息安全性设计准则检查插件 |
||||
* 项目描述:用于检查源代码的安全性设计准则的Sonarqube插件 |
||||
* 版权说明:本软件属北京关键科技股份有限公司所有,在未获得北京关键科技股份有限公司正式授权情况下,任何企业和个人,不能获取、阅读、安装、传播本软件涉及的任何受知识产权保护的内容。 |
||||
*/ |
||||
package com.keyware.sonar.java.rules.checkers; |
||||
|
||||
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 java.io.*; |
||||
import java.util.Properties; |
||||
import java.util.Scanner; |
||||
|
||||
|
||||
/** |
||||
* TODO ConfigurationFileChecker |
||||
* |
||||
* @author WuHaoYang |
||||
* @date 2024/1/22 |
||||
*/ |
||||
@Rule(key = "ConfigurationFileChecker") |
||||
public class ConfigurationFileChecker { |
||||
|
||||
|
||||
public void execute(SensorContext context, InputFile inputFile, RuleKey ruleKey){ |
||||
//文件名称
|
||||
String filename = inputFile.filename(); |
||||
System.out.println("[ConfigurationFileChecker]>>>>>" + filename); |
||||
|
||||
//校验文件后缀
|
||||
if (filename.endsWith(".properties")) { |
||||
try { |
||||
File file = new File(inputFile.absolutePath()); |
||||
try (Scanner scanner = new Scanner(file)) { |
||||
int lineNum = 1; |
||||
while (scanner.hasNextLine()) { |
||||
String line = scanner.nextLine(); |
||||
if (line.contains("password")) { |
||||
System.out.println(line); |
||||
NewIssue newIssue = context.newIssue(); |
||||
newIssue |
||||
.forRule(ruleKey) |
||||
.at(newIssue.newLocation() |
||||
.on(inputFile) |
||||
.at(inputFile.selectLine(lineNum))) |
||||
.save(); |
||||
break; |
||||
} |
||||
lineNum ++; |
||||
} |
||||
} |
||||
} catch (FileNotFoundException e) { |
||||
System.out.println("文件未找到: " + e.getMessage()); |
||||
} |
||||
} |
||||
|
||||
|
||||
if (filename.endsWith(".ini")){ |
||||
// 获取当前输入文件的绝对路径
|
||||
File file1 = inputFile.file(); |
||||
File absoluteFile = file1.getAbsoluteFile(); |
||||
|
||||
// 构建目录路径
|
||||
File folder = new File(String.valueOf(absoluteFile)).getParentFile(); |
||||
System.out.println("---------------ini文件路径----------------"+folder); |
||||
File[] listOfFiles = folder.listFiles(); |
||||
|
||||
int lineNum = 1; |
||||
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); |
||||
NewIssue newIssue = context.newIssue(); |
||||
newIssue |
||||
.forRule(ruleKey) |
||||
.at(newIssue.newLocation() |
||||
.on(inputFile) |
||||
.at(inputFile.selectLine(lineNum))) |
||||
.save(); |
||||
} catch (IOException e) { |
||||
e.printStackTrace(); |
||||
} |
||||
} |
||||
lineNum++; |
||||
} |
||||
} |
||||
|
||||
|
||||
|
||||
if (filename.endsWith(".conf")){ |
||||
// 获取当前输入文件的绝对路径
|
||||
File file1 = inputFile.file(); |
||||
File absoluteFile = file1.getAbsoluteFile(); |
||||
|
||||
// 构建目录路径
|
||||
File folder = new File(String.valueOf(absoluteFile)).getParentFile(); |
||||
|
||||
System.out.println("---------------conf文件路径----------------"+folder); |
||||
|
||||
File[] listOfFiles = folder.listFiles((dir, name) -> name.endsWith(".conf")); |
||||
|
||||
int lineNum = 1; |
||||
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")); |
||||
NewIssue newIssue = context.newIssue(); |
||||
newIssue |
||||
.forRule(ruleKey) |
||||
.at(newIssue.newLocation() |
||||
.on(inputFile) |
||||
.at(inputFile.selectLine(lineNum))) |
||||
.save(); |
||||
} |
||||
|
||||
} catch (IOException ex) { |
||||
ex.printStackTrace(); |
||||
} finally { |
||||
if (input != null) { |
||||
try { |
||||
input.close(); |
||||
} catch (IOException e) { |
||||
e.printStackTrace(); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
lineNum++; |
||||
} |
||||
} |
||||
} |
||||
|
||||
} |
@ -0,0 +1,9 @@ |
||||
<p>禁止在容易受攻击的地方明文存储口令密码</p> |
||||
<h2>禁止在容易受攻击的地方明文存储口令密码,如果需要,考虑存储口令的单向加密散列,以替代明文口令存储。</h2> |
||||
<pre> |
||||
|
||||
</pre> |
||||
<h2>合规解决方案</h2> |
||||
<pre> |
||||
|
||||
</pre> |
@ -0,0 +1,13 @@ |
||||
{ |
||||
"title": "禁止在容易受攻击的地方明文存储口令密码", |
||||
"type": "CODE_SMELL", |
||||
"status": "ready", |
||||
"remediation": { |
||||
"func": "Constant\/Issue", |
||||
"constantCost": "5min" |
||||
}, |
||||
"tags": [ |
||||
"28suo" |
||||
], |
||||
"defaultSeverity": "Minor" |
||||
} |
@ -0,0 +1,2 @@ |
||||
# 这是一个conf配置文件 |
||||
password = yourpassword |
@ -0,0 +1,3 @@ |
||||
[UserCredentials] |
||||
username = exampleUser |
||||
password = examplePassword |
@ -0,0 +1,2 @@ |
||||
# ConfigurationFileChecker.properties |
||||
password=abc123 |
Loading…
Reference in new issue