parent
b4147782d6
commit
e76715936e
@ -0,0 +1,268 @@ |
|||||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" |
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
||||||
|
<modelVersion>4.0.0</modelVersion> |
||||||
|
|
||||||
|
<parent> |
||||||
|
<groupId>com.keyware.sonar</groupId> |
||||||
|
<artifactId>sonar-keyware</artifactId> |
||||||
|
<version>1.0</version> |
||||||
|
</parent> |
||||||
|
|
||||||
|
<name>配置文件信息安全性设计准则</name> |
||||||
|
<artifactId>sonar-keyware-plugins-configurationDetection</artifactId> |
||||||
|
<packaging>sonar-plugin</packaging> |
||||||
|
<version>1.0</version> |
||||||
|
<description>用于检查配置文件信息的安全性设计准则的Sonarqube插件</description> |
||||||
|
|
||||||
|
<properties> |
||||||
|
<sonar.sources>src/main/java,src/main/resources</sonar.sources> |
||||||
|
</properties> |
||||||
|
|
||||||
|
<dependencies> |
||||||
|
|
||||||
|
|
||||||
|
<dependency> |
||||||
|
<groupId>org.sonarsource.api.plugin</groupId> |
||||||
|
<artifactId>sonar-plugin-api</artifactId> |
||||||
|
<version>9.9.0.229</version> |
||||||
|
<scope>provided</scope> |
||||||
|
</dependency> |
||||||
|
|
||||||
|
<dependency> |
||||||
|
<groupId>org.slf4j</groupId> |
||||||
|
<artifactId>slf4j-api</artifactId> |
||||||
|
<scope>provided</scope> |
||||||
|
</dependency> |
||||||
|
|
||||||
|
<dependency> |
||||||
|
<groupId>org.sonarsource.html</groupId> |
||||||
|
<artifactId>sonar-html-plugin</artifactId> |
||||||
|
<version>${sonar.html.version}</version> |
||||||
|
<!--<type>sonar-plugin</type>--> |
||||||
|
<scope>compile</scope> |
||||||
|
</dependency> |
||||||
|
|
||||||
|
<dependency> |
||||||
|
<groupId>org.sonarsource.analyzer-commons</groupId> |
||||||
|
<artifactId>sonar-analyzer-commons</artifactId> |
||||||
|
</dependency> |
||||||
|
<dependency> |
||||||
|
<groupId>org.apache.logging.log4j</groupId> |
||||||
|
<artifactId>log4j-slf4j-impl</artifactId> |
||||||
|
<scope>test</scope> |
||||||
|
</dependency> |
||||||
|
|
||||||
|
<dependency> |
||||||
|
<groupId>org.apache.logging.log4j</groupId> |
||||||
|
<artifactId>log4j-core</artifactId> |
||||||
|
<scope>test</scope> |
||||||
|
</dependency> |
||||||
|
|
||||||
|
<!-- unit tests --> |
||||||
|
<dependency> |
||||||
|
<groupId>org.assertj</groupId> |
||||||
|
<artifactId>assertj-core</artifactId> |
||||||
|
<scope>test</scope> |
||||||
|
</dependency> |
||||||
|
<dependency> |
||||||
|
<groupId>org.junit.jupiter</groupId> |
||||||
|
<artifactId>junit-jupiter</artifactId> |
||||||
|
<scope>test</scope> |
||||||
|
</dependency> |
||||||
|
<dependency> |
||||||
|
<groupId>org.junit.jupiter</groupId> |
||||||
|
<artifactId>junit-jupiter-api</artifactId> |
||||||
|
<scope>test</scope> |
||||||
|
</dependency> |
||||||
|
<dependency> |
||||||
|
<groupId>org.junit.jupiter</groupId> |
||||||
|
<artifactId>junit-jupiter-engine</artifactId> |
||||||
|
<scope>test</scope> |
||||||
|
</dependency> |
||||||
|
<dependency> |
||||||
|
<groupId>org.junit.jupiter</groupId> |
||||||
|
<artifactId>junit-jupiter-migrationsupport</artifactId> |
||||||
|
<scope>test</scope> |
||||||
|
</dependency> |
||||||
|
<dependency> |
||||||
|
<groupId>org.sonarsource.sonarqube</groupId> |
||||||
|
<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> |
||||||
|
|
||||||
|
<dependency> |
||||||
|
<groupId>com.fasterxml.jackson.core</groupId> |
||||||
|
<artifactId>jackson-core</artifactId> |
||||||
|
<version>2.12.3</version> |
||||||
|
</dependency> |
||||||
|
<dependency> |
||||||
|
<groupId>xerces</groupId> |
||||||
|
<artifactId>xercesImpl</artifactId> |
||||||
|
<version>2.12.2</version> |
||||||
|
<scope>compile</scope> |
||||||
|
</dependency> |
||||||
|
|
||||||
|
<dependency> |
||||||
|
<groupId>com.fasterxml.jackson.dataformat</groupId> |
||||||
|
<artifactId>jackson-dataformat-yaml</artifactId> |
||||||
|
<version>2.16.1</version> |
||||||
|
</dependency> |
||||||
|
|
||||||
|
</dependencies> |
||||||
|
|
||||||
|
<build> |
||||||
|
<plugins> |
||||||
|
<plugin> |
||||||
|
<groupId>org.sonarsource.sonar-packaging-maven-plugin</groupId> |
||||||
|
<artifactId>sonar-packaging-maven-plugin</artifactId> |
||||||
|
<extensions>true</extensions> |
||||||
|
<configuration> |
||||||
|
<pluginKey>keywareConfigurationDetectionPlugin</pluginKey> |
||||||
|
<pluginName>配置文件信息设计准则</pluginName> |
||||||
|
<pluginClass>com.keyware.sonar.Configuration.ConfigurationSecurityDesignRulesPlugin</pluginClass> |
||||||
|
<sonarLintSupported>true</sonarLintSupported> |
||||||
|
<skipDependenciesPackaging>true</skipDependenciesPackaging> |
||||||
|
<sonarQubeMinVersion>8.9</sonarQubeMinVersion> |
||||||
|
<jreMinVersion>11</jreMinVersion> |
||||||
|
</configuration> |
||||||
|
</plugin> |
||||||
|
|
||||||
|
<plugin> |
||||||
|
<groupId>org.apache.maven.plugins</groupId> |
||||||
|
<artifactId>maven-shade-plugin</artifactId> |
||||||
|
<configuration> |
||||||
|
</configuration> |
||||||
|
<executions> |
||||||
|
<execution> |
||||||
|
<phase>package</phase> |
||||||
|
<goals> |
||||||
|
<goal>shade</goal> |
||||||
|
</goals> |
||||||
|
</execution> |
||||||
|
</executions> |
||||||
|
</plugin> |
||||||
|
|
||||||
|
<plugin> |
||||||
|
<groupId>org.apache.maven.plugins</groupId> |
||||||
|
<artifactId>maven-compiler-plugin</artifactId> |
||||||
|
<configuration> |
||||||
|
<source>11</source> |
||||||
|
<target>11</target> |
||||||
|
</configuration> |
||||||
|
</plugin> |
||||||
|
|
||||||
|
<plugin> |
||||||
|
<groupId>org.jacoco</groupId> |
||||||
|
<artifactId>jacoco-maven-plugin</artifactId> |
||||||
|
<version>${version.jacoco.plugin}</version> |
||||||
|
<executions> |
||||||
|
<execution> |
||||||
|
<id>prepare-agent</id> |
||||||
|
<goals> |
||||||
|
<goal>prepare-agent</goal> |
||||||
|
</goals> |
||||||
|
</execution> |
||||||
|
<execution> |
||||||
|
<id>report</id> |
||||||
|
<goals> |
||||||
|
<goal>report</goal> |
||||||
|
</goals> |
||||||
|
</execution> |
||||||
|
</executions> |
||||||
|
</plugin> |
||||||
|
|
||||||
|
<!-- only required to run UT - these are UT dependencies --> |
||||||
|
<plugin> |
||||||
|
<groupId>org.apache.maven.plugins</groupId> |
||||||
|
<artifactId>maven-dependency-plugin</artifactId> |
||||||
|
<executions> |
||||||
|
<execution> |
||||||
|
<id>copy</id> |
||||||
|
<phase>test-compile</phase> |
||||||
|
<goals> |
||||||
|
<goal>copy</goal> |
||||||
|
</goals> |
||||||
|
<configuration> |
||||||
|
<artifactItems> |
||||||
|
<artifactItem> |
||||||
|
<groupId>org.slf4j</groupId> |
||||||
|
<artifactId>slf4j-api</artifactId> |
||||||
|
<version>1.7.30</version> |
||||||
|
<type>jar</type> |
||||||
|
</artifactItem> |
||||||
|
<artifactItem> |
||||||
|
<groupId>org.apache.commons</groupId> |
||||||
|
<artifactId>commons-collections4</artifactId> |
||||||
|
<version>4.0</version> |
||||||
|
<type>jar</type> |
||||||
|
</artifactItem> |
||||||
|
<artifactItem> |
||||||
|
<groupId>javax</groupId> |
||||||
|
<artifactId>javaee-api</artifactId> |
||||||
|
<version>6.0</version> |
||||||
|
<type>jar</type> |
||||||
|
</artifactItem> |
||||||
|
<artifactItem> |
||||||
|
<groupId>org.springframework</groupId> |
||||||
|
<artifactId>spring-webmvc</artifactId> |
||||||
|
<version>4.3.3.RELEASE</version> |
||||||
|
<type>jar</type> |
||||||
|
</artifactItem> |
||||||
|
<artifactItem> |
||||||
|
<groupId>org.springframework</groupId> |
||||||
|
<artifactId>spring-web</artifactId> |
||||||
|
<version>4.3.3.RELEASE</version> |
||||||
|
<type>jar</type> |
||||||
|
</artifactItem> |
||||||
|
<artifactItem> |
||||||
|
<groupId>org.springframework</groupId> |
||||||
|
<artifactId>spring-context</artifactId> |
||||||
|
<version>4.3.3.RELEASE</version> |
||||||
|
<type>jar</type> |
||||||
|
</artifactItem> |
||||||
|
<artifactItem> |
||||||
|
<groupId>junit</groupId> |
||||||
|
<artifactId>junit</artifactId> |
||||||
|
<version>4.13.2</version> |
||||||
|
<type>jar</type> |
||||||
|
</artifactItem> |
||||||
|
</artifactItems> |
||||||
|
<outputDirectory>${project.build.directory}/test-jars</outputDirectory> |
||||||
|
</configuration> |
||||||
|
</execution> |
||||||
|
</executions> |
||||||
|
</plugin> |
||||||
|
<plugin> |
||||||
|
<groupId>com.mycila</groupId> |
||||||
|
<artifactId>license-maven-plugin</artifactId> |
||||||
|
<configuration> |
||||||
|
<header>${project.basedir}/src/main/resources/license-header.txt</header> |
||||||
|
<!--排除文件--> |
||||||
|
<excludes> |
||||||
|
<exclude>**/*.properties</exclude> |
||||||
|
<exclude>*.sh</exclude> |
||||||
|
<exclude>*.yml</exclude> |
||||||
|
<exclude>.editorconfig</exclude> |
||||||
|
<exclude>.gitignore</exclude> |
||||||
|
<exclude>**/*.md</exclude> |
||||||
|
<exclude>**/*.xml</exclude> |
||||||
|
</excludes> |
||||||
|
</configuration> |
||||||
|
</plugin> |
||||||
|
</plugins> |
||||||
|
</build> |
||||||
|
</project> |
@ -0,0 +1,37 @@ |
|||||||
|
/* |
||||||
|
* Copyright (c) 2023 - 2024. KeyWare.Co.Ltd All rights reserved. |
||||||
|
* 项目名称:信息安全性设计准则检查插件 |
||||||
|
* 项目描述:用于检查源代码的安全性设计准则的Sonarqube插件 |
||||||
|
* 版权说明:本软件属北京关键科技股份有限公司所有,在未获得北京关键科技股份有限公司正式授权情况下,任何企业和个人,不能获取、阅读、安装、传播本软件涉及的任何受知识产权保护的内容。 |
||||||
|
*/ |
||||||
|
package com.keyware.sonar.Configuration; |
||||||
|
|
||||||
|
import com.keyware.sonar.Configuration.rules.ConfigurationSecurityDesignRulesRepository; |
||||||
|
import org.sonar.api.Plugin; |
||||||
|
|
||||||
|
/** |
||||||
|
* 安全性设计准则插件 |
||||||
|
* |
||||||
|
* @author GuoXin |
||||||
|
* @date 2024/1/6 |
||||||
|
*/ |
||||||
|
public class ConfigurationSecurityDesignRulesPlugin implements Plugin { |
||||||
|
@Override |
||||||
|
public void define(Context context) { |
||||||
|
// 服务器扩展 - >对象在服务器启动期间实例化
|
||||||
|
context.addExtension(ConfigurationSecurityDesignRulesRepository.class); |
||||||
|
|
||||||
|
// 服务器扩展 - >对象在服务器启动期间实例化
|
||||||
|
context.addExtension(ConfigurationSecurityDesignWayProfile.class); |
||||||
|
|
||||||
|
|
||||||
|
context.addExtension(ConfigurationFileLanguage.class); |
||||||
|
|
||||||
|
|
||||||
|
context.addExtension(ConfigFileSquidSensor.class); |
||||||
|
|
||||||
|
|
||||||
|
context.addExtensions(ConfigurationFileLanguage.getProperties()); |
||||||
|
|
||||||
|
} |
||||||
|
} |
@ -0,0 +1,29 @@ |
|||||||
|
/* |
||||||
|
* Copyright (c) 2023 - 2024. KeyWare.Co.Ltd All rights reserved. |
||||||
|
* 项目名称:信息安全性设计准则检查插件 |
||||||
|
* 项目描述:用于检查源代码的安全性设计准则的Sonarqube插件 |
||||||
|
* 版权说明:本软件属北京关键科技股份有限公司所有,在未获得北京关键科技股份有限公司正式授权情况下,任何企业和个人,不能获取、阅读、安装、传播本软件涉及的任何受知识产权保护的内容。 |
||||||
|
*/ |
||||||
|
package com.keyware.sonar.Configuration; |
||||||
|
|
||||||
|
import org.sonar.api.server.profile.BuiltInQualityProfilesDefinition; |
||||||
|
import org.sonarsource.api.sonarlint.SonarLintSide; |
||||||
|
|
||||||
|
/** |
||||||
|
* 定义配置信息安全性质量配置 |
||||||
|
* |
||||||
|
* @author GuoXin |
||||||
|
* @date 2024/1/11 |
||||||
|
*/ |
||||||
|
@SonarLintSide |
||||||
|
public class ConfigurationSecurityDesignWayProfile implements BuiltInQualityProfilesDefinition { |
||||||
|
|
||||||
|
@Override |
||||||
|
public void define(Context context) { |
||||||
|
|
||||||
|
var cfgWay = context.createBuiltInQualityProfile("配置信息安全性设计规则", ConfigurationFileLanguage.KEY); |
||||||
|
cfgWay.activateRule("config", "ConfigurationFileChecker"); |
||||||
|
cfgWay.activateRule("config", "SessionDateChecker"); |
||||||
|
cfgWay.done(); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,55 @@ |
|||||||
|
/* |
||||||
|
* Copyright (c) 2023 - 2024. KeyWare.Co.Ltd All rights reserved. |
||||||
|
* 项目名称:信息安全性设计准则检查插件 |
||||||
|
* 项目描述:用于检查源代码的安全性设计准则的Sonarqube插件 |
||||||
|
* 版权说明:本软件属北京关键科技股份有限公司所有,在未获得北京关键科技股份有限公司正式授权情况下,任何企业和个人,不能获取、阅读、安装、传播本软件涉及的任何受知识产权保护的内容。 |
||||||
|
*/ |
||||||
|
package com.keyware.sonar.Configuration.rules; |
||||||
|
|
||||||
|
import com.keyware.sonar.Configuration.rules.checkers.SessionDateChecker; |
||||||
|
import com.keyware.sonar.Configuration.rules.checkers.ConfigurationFileChecker; |
||||||
|
import org.sonar.api.SonarRuntime; |
||||||
|
import org.sonar.api.server.rule.RulesDefinition; |
||||||
|
import org.sonarsource.analyzer.commons.RuleMetadataLoader; |
||||||
|
|
||||||
|
import java.util.*; |
||||||
|
|
||||||
|
/** |
||||||
|
* 用于定义出现在规则页面中规则的元数据 |
||||||
|
* |
||||||
|
* @author GuoXin |
||||||
|
* @date 2024/1/6 |
||||||
|
*/ |
||||||
|
public class ConfigurationSecurityDesignRulesRepository implements RulesDefinition { |
||||||
|
// 不要修改这个值,因为路径在 CheckVerifier 中是硬编码的
|
||||||
|
private static final String RESOURCE_BASE_PATH = "org/sonar/l10n/java/rules/java"; |
||||||
|
|
||||||
|
// 添加需要视为模板规则的规则的规则键
|
||||||
|
private static final Set<String> RULE_TEMPLATES_KEY = Collections.emptySet(); |
||||||
|
|
||||||
|
private final SonarRuntime runtime; |
||||||
|
|
||||||
|
public ConfigurationSecurityDesignRulesRepository(SonarRuntime runtime) { |
||||||
|
this.runtime = runtime; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void define(RulesDefinition.Context context) { |
||||||
|
RuleMetadataLoader ruleMetadataLoader = new RuleMetadataLoader(RESOURCE_BASE_PATH, runtime); |
||||||
|
|
||||||
|
|
||||||
|
RulesDefinition.NewRepository configRepo = context.createRepository("config", "cfg").setName("config"); |
||||||
|
ruleMetadataLoader.addRulesByAnnotatedClass(configRepo, List.of(ConfigurationFileChecker.class, SessionDateChecker.class)); |
||||||
|
setTemplates(configRepo); |
||||||
|
configRepo.done(); |
||||||
|
} |
||||||
|
|
||||||
|
private static void setTemplates(RulesDefinition.NewRepository repository) { |
||||||
|
RULE_TEMPLATES_KEY.stream() |
||||||
|
.map(repository::rule) |
||||||
|
.filter(Objects::nonNull) |
||||||
|
.forEach(rule -> rule.setTemplate(true)); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
} |
@ -0,0 +1,23 @@ |
|||||||
|
/* |
||||||
|
* Copyright (c) 2023 - 2024. KeyWare.Co.Ltd All rights reserved. |
||||||
|
* 项目名称:信息安全性设计准则检查插件 |
||||||
|
* 项目描述:用于检查源代码的安全性设计准则的Sonarqube插件 |
||||||
|
* 版权说明:本软件属北京关键科技股份有限公司所有,在未获得北京关键科技股份有限公司正式授权情况下,任何企业和个人,不能获取、阅读、安装、传播本软件涉及的任何受知识产权保护的内容。 |
||||||
|
*/ |
||||||
|
|
||||||
|
package com.keyware.sonar.Configuration.rules.checkers; |
||||||
|
|
||||||
|
import org.sonar.api.batch.fs.InputFile; |
||||||
|
import org.sonar.api.batch.sensor.SensorContext; |
||||||
|
import org.sonar.api.rule.RuleKey; |
||||||
|
|
||||||
|
/** |
||||||
|
* ConfigCheck |
||||||
|
* |
||||||
|
* @author RenFengJiang |
||||||
|
* @date 2024/1/23 |
||||||
|
*/ |
||||||
|
public interface ConfigCheck { |
||||||
|
default void execute(SensorContext context, InputFile inputFile, RuleKey ruleKey){} |
||||||
|
default void endOfCheck(SensorContext context, RuleKey ruleKey){} |
||||||
|
} |
@ -0,0 +1,250 @@ |
|||||||
|
/* |
||||||
|
* Copyright (c) 2023 - 2024. KeyWare.Co.Ltd All rights reserved. |
||||||
|
* 项目名称:信息安全性设计准则检查插件 |
||||||
|
* 项目描述:用于检查源代码的安全性设计准则的Sonarqube插件 |
||||||
|
* 版权说明:本软件属北京关键科技股份有限公司所有,在未获得北京关键科技股份有限公司正式授权情况下,任何企业和个人,不能获取、阅读、安装、传播本软件涉及的任何受知识产权保护的内容。 |
||||||
|
*/ |
||||||
|
package com.keyware.sonar.Configuration.rules.checkers; |
||||||
|
|
||||||
|
import com.fasterxml.jackson.core.JsonFactory; |
||||||
|
import com.fasterxml.jackson.core.JsonParser; |
||||||
|
import com.fasterxml.jackson.core.JsonToken; |
||||||
|
import com.fasterxml.jackson.databind.MappingJsonFactory; |
||||||
|
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.*; |
||||||
|
import java.io.*; |
||||||
|
import java.util.Map; |
||||||
|
import java.util.Scanner; |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* 通过用户名口令、数据证书等其他手段对用户身份进行验证。 |
||||||
|
* |
||||||
|
* @author WuHaoYang |
||||||
|
* @date 2024/1/22 |
||||||
|
*/ |
||||||
|
@Rule(key = "ConfigurationFileChecker") |
||||||
|
public class ConfigurationFileChecker implements ConfigCheck{ |
||||||
|
|
||||||
|
|
||||||
|
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(); |
||||||
|
|
||||||
|
String[] keyValue = line.split("="); // 分割行的内容
|
||||||
|
|
||||||
|
// 检查键是否为 "password" 且其对应的值不为空
|
||||||
|
if (keyValue.length == 2 && keyValue[0].trim().equals("password") |
||||||
|
&& !keyValue[1].trim().isEmpty()) { |
||||||
|
NewIssue newIssue = context.newIssue(); |
||||||
|
newIssue.forRule(ruleKey) |
||||||
|
.at(newIssue.newLocation() |
||||||
|
.on(inputFile) |
||||||
|
.at(inputFile.selectLine(lineNum))) |
||||||
|
.save(); |
||||||
|
} |
||||||
|
lineNum++; |
||||||
|
} |
||||||
|
} |
||||||
|
} catch (FileNotFoundException e) { |
||||||
|
System.out.println("文件未找到: " + e.getMessage()); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if (filename.endsWith(".ini")) { |
||||||
|
// 获取当前输入文件的绝对路径
|
||||||
|
File file1 = inputFile.file(); |
||||||
|
|
||||||
|
try (BufferedReader br = new BufferedReader(new FileReader(file1))) { |
||||||
|
String line; |
||||||
|
int lineNum = 1; |
||||||
|
while ((line = br.readLine()) != null) { |
||||||
|
if (line.trim().startsWith("password")) { |
||||||
|
NewIssue newIssue = context.newIssue(); |
||||||
|
newIssue.forRule(ruleKey) |
||||||
|
.at(newIssue.newLocation() |
||||||
|
.on(inputFile) |
||||||
|
.at(inputFile.selectLine(lineNum))) |
||||||
|
.save(); |
||||||
|
break; |
||||||
|
} |
||||||
|
lineNum++; |
||||||
|
} |
||||||
|
} catch (IOException e) { |
||||||
|
e.printStackTrace(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if (filename.endsWith(".conf")) { |
||||||
|
// 获取当前输入文件的绝对路径
|
||||||
|
File file1 = inputFile.file(); |
||||||
|
|
||||||
|
int lineNum = 0; // 初始化行数
|
||||||
|
|
||||||
|
try { |
||||||
|
BufferedReader br = new BufferedReader(new FileReader(file1)); |
||||||
|
String line; |
||||||
|
|
||||||
|
while ((line = br.readLine()) != null) { |
||||||
|
lineNum++; // 递增行数
|
||||||
|
|
||||||
|
String[] keyValue = line.split("="); // 分割行的内容
|
||||||
|
|
||||||
|
// 进行基本有效性检查 && keyValue[0]可能包含前导空格, keyValue[1]可能包含尾随空格
|
||||||
|
if (keyValue.length == 2 && keyValue[0].trim().equals("password")) { |
||||||
|
|
||||||
|
// 如果键是 "password", 输出其值
|
||||||
|
NewIssue newIssue = context.newIssue(); |
||||||
|
newIssue |
||||||
|
.forRule(ruleKey) |
||||||
|
.at(newIssue.newLocation() |
||||||
|
.on(inputFile) |
||||||
|
.at(inputFile.selectLine(lineNum))) |
||||||
|
.save(); |
||||||
|
} |
||||||
|
} |
||||||
|
br.close(); |
||||||
|
} catch(FileNotFoundException ex) { |
||||||
|
ex.printStackTrace(); |
||||||
|
} catch(IOException ex) { |
||||||
|
ex.printStackTrace(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if (filename.endsWith(".xml") && !filename.equals("pom.xml")){ |
||||||
|
// 获取当前输入文件的绝对路径
|
||||||
|
File file1 = inputFile.file(); |
||||||
|
|
||||||
|
File absoluteFile = file1.getAbsoluteFile(); |
||||||
|
|
||||||
|
File xmlFile = absoluteFile; |
||||||
|
|
||||||
|
processXML(xmlFile); |
||||||
|
} |
||||||
|
|
||||||
|
if (filename.endsWith(".json")) { |
||||||
|
try { |
||||||
|
// 获取当前输入文件的绝对路径
|
||||||
|
File file1 = inputFile.file(); |
||||||
|
|
||||||
|
JsonFactory f = new MappingJsonFactory(); |
||||||
|
JsonParser jp = f.createParser(file1); |
||||||
|
JsonToken current; |
||||||
|
|
||||||
|
current = jp.nextToken(); |
||||||
|
if (current != JsonToken.START_OBJECT) { |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
while (jp.nextToken() != JsonToken.END_OBJECT) { |
||||||
|
String fieldName = jp.getCurrentName(); |
||||||
|
current = jp.nextToken(); |
||||||
|
|
||||||
|
if ("password".equals(fieldName)) { |
||||||
|
|
||||||
|
int lineNum = jp.getCurrentLocation().getLineNr(); |
||||||
|
|
||||||
|
String passwordValue = jp.getText(); |
||||||
|
|
||||||
|
NewIssue newIssue = context.newIssue(); |
||||||
|
newIssue |
||||||
|
.forRule(ruleKey) |
||||||
|
.at(newIssue.newLocation() |
||||||
|
.on(inputFile) |
||||||
|
.at(inputFile.selectLine(lineNum))) |
||||||
|
.save(); |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
} catch (IOException e) { |
||||||
|
e.printStackTrace(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if (filename.endsWith(".yml")){ |
||||||
|
|
||||||
|
// 获取当前输入文件的绝对路径
|
||||||
|
File file1 = inputFile.file(); |
||||||
|
|
||||||
|
Yaml yaml = new Yaml(); |
||||||
|
try (FileInputStream fis = new FileInputStream(file1)) { |
||||||
|
Map<String, Object> obj = yaml.load(fis); |
||||||
|
if (obj != null) { |
||||||
|
String password = searchPassword(obj, 1); |
||||||
|
if (password != null) { |
||||||
|
} |
||||||
|
} |
||||||
|
} catch (IOException e) { |
||||||
|
e.printStackTrace(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
private static String searchPassword(Map<String, Object> map, int lineNum) { |
||||||
|
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) { |
||||||
|
lineNum++; |
||||||
|
String password = searchPassword((Map<String, Object>) map.get(key), lineNum); |
||||||
|
if (password != null) { |
||||||
|
return password; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
public static int getLineNumber(Node node) { |
||||||
|
Document document = node.getOwnerDocument(); |
||||||
|
document.getDocumentElement().normalize(); |
||||||
|
String xmlContent = document.getDocumentElement().getTextContent(); |
||||||
|
String[] lines = xmlContent.split("\n"); |
||||||
|
for(int i = 0; i < lines.length; i++) { |
||||||
|
if(lines[i].contains(node.getTextContent())) { |
||||||
|
return i+2; |
||||||
|
} |
||||||
|
} |
||||||
|
return -1; |
||||||
|
} |
||||||
|
|
||||||
|
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; |
||||||
|
int lineNumber = getLineNumber(nNode); |
||||||
|
} |
||||||
|
} |
||||||
|
} catch (Exception e) { |
||||||
|
e.printStackTrace(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,96 @@ |
|||||||
|
/* |
||||||
|
* Copyright (c) 2023 - 2024. KeyWare.Co.Ltd All rights reserved. |
||||||
|
* 项目名称:信息安全性设计准则检查插件 |
||||||
|
* 项目描述:用于检查源代码的安全性设计准则的Sonarqube插件 |
||||||
|
* 版权说明:本软件属北京关键科技股份有限公司所有,在未获得北京关键科技股份有限公司正式授权情况下,任何企业和个人,不能获取、阅读、安装、传播本软件涉及的任何受知识产权保护的内容。 |
||||||
|
*/ |
||||||
|
|
||||||
|
package com.keyware.sonar.Configuration.rules.checkers; |
||||||
|
|
||||||
|
import org.sonar.api.batch.fs.InputFile; |
||||||
|
import org.sonar.api.batch.sensor.SensorContext; |
||||||
|
import org.sonar.api.rule.RuleKey; |
||||||
|
import org.sonar.check.Rule; |
||||||
|
import org.yaml.snakeyaml.Yaml; |
||||||
|
|
||||||
|
import java.io.File; |
||||||
|
import java.io.FileInputStream; |
||||||
|
import java.io.FileNotFoundException; |
||||||
|
import java.io.IOException; |
||||||
|
import java.util.Map; |
||||||
|
import java.util.Scanner; |
||||||
|
|
||||||
|
/** |
||||||
|
* 设置会话过期的日期 |
||||||
|
* |
||||||
|
* @author RenFengJiang |
||||||
|
* @date 2024/1/22 |
||||||
|
*/ |
||||||
|
@Rule(key = "SessionDateChecker") |
||||||
|
public class SessionDateChecker implements ConfigCheck { |
||||||
|
|
||||||
|
private boolean boo = true; |
||||||
|
public void execute(SensorContext context, InputFile inputFile, RuleKey ruleKey){ |
||||||
|
if(boo){ |
||||||
|
//文件名称
|
||||||
|
String filename = inputFile.filename(); |
||||||
|
//校验文件后缀
|
||||||
|
if (filename.endsWith(".properties")) { |
||||||
|
try { |
||||||
|
File file = new File(inputFile.absolutePath()); |
||||||
|
try (Scanner scanner = new Scanner(file)) { |
||||||
|
while (scanner.hasNextLine()) { |
||||||
|
String line = scanner.nextLine(); |
||||||
|
if (line.contains("server.servlet.session.timeout")) { |
||||||
|
boo = false; |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} catch (FileNotFoundException e) { |
||||||
|
System.out.println("文件未找到: " + e.getMessage()); |
||||||
|
return; // 文件未找到时立即返回
|
||||||
|
} |
||||||
|
} |
||||||
|
if (filename.endsWith(".yml")){ |
||||||
|
// 获取当前输入文件的绝对路径
|
||||||
|
File file1 = inputFile.file(); |
||||||
|
File absoluteFile = file1.getAbsoluteFile(); |
||||||
|
// 构建目录路径
|
||||||
|
Yaml yaml = new Yaml(); |
||||||
|
try (FileInputStream fis = new FileInputStream(file1)) { |
||||||
|
Map<String, Object> obj = yaml.load(fis); |
||||||
|
if (obj != null){ |
||||||
|
String sessionTimeout = searchForSessionTimeout(obj, "server", "servlet", "session", "timeout"); |
||||||
|
if (sessionTimeout != null) { |
||||||
|
boo = false; |
||||||
|
} |
||||||
|
} |
||||||
|
} catch (IOException e) { |
||||||
|
e.printStackTrace(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private String searchForSessionTimeout(Map<String, Object> map, String... keys) { |
||||||
|
Map<String, Object> currentLevel = map; |
||||||
|
for (int i = 0; i < keys.length - 1; ++i) { |
||||||
|
Object nextLevel = currentLevel.get(keys[i]); |
||||||
|
if (nextLevel instanceof Map) { |
||||||
|
currentLevel = (Map<String, Object>) nextLevel; |
||||||
|
} else { |
||||||
|
return null; |
||||||
|
} |
||||||
|
} |
||||||
|
return currentLevel.get(keys[keys.length - 1]).toString(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void endOfCheck(SensorContext context, RuleKey ruleKey) { |
||||||
|
if(boo){ |
||||||
|
var issue = context.newIssue(); |
||||||
|
issue.at(issue.newLocation().on(context.project()).message("设置会话过期的日期")).forRule(ruleKey).save(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,13 @@ |
|||||||
|
/* |
||||||
|
* Copyright (c) 2023 - 2024. KeyWare.Co.Ltd All rights reserved. |
||||||
|
* 项目名称:信息安全性设计准则检查插件 |
||||||
|
* 项目描述:用于检查源代码的安全性设计准则的Sonarqube插件 |
||||||
|
* 版权说明:本软件属北京关键科技股份有限公司所有,在未获得北京关键科技股份有限公司正式授权情况下,任何企业和个人,不能获取、阅读、安装、传播本软件涉及的任何受知识产权保护的内容。 |
||||||
|
*/ |
||||||
|
/** |
||||||
|
* TODO package-info |
||||||
|
* |
||||||
|
* @author GuoXin |
||||||
|
* @date 2024/1/12 |
||||||
|
*/ |
||||||
|
package com.keyware.sonar.Configuration.rules; |
@ -0,0 +1,4 @@ |
|||||||
|
Copyright (c) 2023 - 2024. KeyWare.Co.Ltd All rights reserved. |
||||||
|
项目名称:信息安全性设计准则检查插件 |
||||||
|
项目描述:用于检查源代码的安全性设计准则的Sonarqube插件 |
||||||
|
版权说明:本软件属北京关键科技股份有限公司所有,在未获得北京关键科技股份有限公司正式授权情况下,任何企业和个人,不能获取、阅读、安装、传播本软件涉及的任何受知识产权保护的内容。 |
@ -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,16 @@ |
|||||||
|
<!-- |
||||||
|
~ Copyright (c) 2023 - 2024. KeyWare.Co.Ltd All rights reserved. |
||||||
|
~ 项目名称:信息安全性设计准则检查插件 |
||||||
|
~ 项目描述:用于检查源代码的安全性设计准则的Sonarqube插件 |
||||||
|
~ 版权说明:本软件属北京关键科技股份有限公司所有,在未获得北京关键科技股份有限公司正式授权情况下,任何企业和个人,不能获取、阅读、安装、传播本软件涉及的任何受知识产权保护的内容。 |
||||||
|
--> |
||||||
|
|
||||||
|
<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 = confPassword |
@ -0,0 +1,3 @@ |
|||||||
|
[UserCredentials] |
||||||
|
username = exampleUser |
||||||
|
password = iniPassword |
@ -0,0 +1,5 @@ |
|||||||
|
{ |
||||||
|
"username": "john_doe", |
||||||
|
"password": "jsonPassword", |
||||||
|
"email": "john.doe@example.com" |
||||||
|
} |
@ -0,0 +1,2 @@ |
|||||||
|
# ConfigurationFileChecker.properties |
||||||
|
password=propertiesPassword |
@ -0,0 +1,7 @@ |
|||||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||||
|
|
||||||
|
<user> |
||||||
|
<username>exampleUser</username> |
||||||
|
<password>xmlPassword</password> |
||||||
|
</user> |
||||||
|
|
@ -0,0 +1,3 @@ |
|||||||
|
database: |
||||||
|
user: admin |
||||||
|
password: ymlPassword |
@ -0,0 +1,9 @@ |
|||||||
|
# |
||||||
|
# Copyright (c) 2023 - 2024. KeyWare.Co.Ltd All rights reserved. |
||||||
|
# 项目名称:信息安全性设计准则检查插件 |
||||||
|
# 项目描述:用于检查源代码的安全性设计准则的Sonarqube插件 |
||||||
|
# 版权说明:本软件属北京关键科技股份有限公司所有,在未获得北京关键科技股份有限公司正式授权情况下,任何企业和个人,不能获取、阅读、安装、传播本软件涉及的任何受知识产权保护的内容。 |
||||||
|
# |
||||||
|
|
||||||
|
# 设置会话超时时间为30分钟 |
||||||
|
server.servlet.session.timeout=30m |
@ -0,0 +1,4 @@ |
|||||||
|
server: |
||||||
|
servlet: |
||||||
|
session: |
||||||
|
timeout: 30m |
@ -0,0 +1,70 @@ |
|||||||
|
/* |
||||||
|
* Copyright (c) 2023 - 2024. KeyWare.Co.Ltd All rights reserved. |
||||||
|
* 项目名称:信息安全性设计准则检查插件 |
||||||
|
* 项目描述:用于检查源代码的安全性设计准则的Sonarqube插件 |
||||||
|
* 版权说明:本软件属北京关键科技股份有限公司所有,在未获得北京关键科技股份有限公司正式授权情况下,任何企业和个人,不能获取、阅读、安装、传播本软件涉及的任何受知识产权保护的内容。 |
||||||
|
*/ |
||||||
|
package com.keyware.sonar.java; |
||||||
|
|
||||||
|
import com.keyware.sonar.Configuration.ConfigurationSecurityDesignRulesPlugin; |
||||||
|
import org.junit.jupiter.api.Test; |
||||||
|
import org.sonar.api.*; |
||||||
|
import org.sonar.api.config.PropertyDefinition; |
||||||
|
import org.sonar.api.utils.Version; |
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat; |
||||||
|
|
||||||
|
/** |
||||||
|
* TODO JavaSecurityDesignRulesPluginTest |
||||||
|
* |
||||||
|
* @author GuoXin |
||||||
|
* @date 2024/1/6 |
||||||
|
*/ |
||||||
|
public class ConfigurationSecurityDesignRulesPluginTest { |
||||||
|
@Test |
||||||
|
void testName() { |
||||||
|
Plugin.Context context = new Plugin.Context(new MockedSonarRuntime()); |
||||||
|
|
||||||
|
new ConfigurationSecurityDesignRulesPlugin().define(context); |
||||||
|
|
||||||
|
assertThat(context.getExtensions()) |
||||||
|
.extracting((ext) -> { |
||||||
|
var type = ext.getClass().getSimpleName(); |
||||||
|
if("Class".equals(type)){ |
||||||
|
return ((Class) ext).getSimpleName(); |
||||||
|
}else if("PropertyDefinition".equals(type)){ |
||||||
|
return ((PropertyDefinition) ext).name(); |
||||||
|
} |
||||||
|
return ext.getClass().getSimpleName(); |
||||||
|
}) |
||||||
|
.containsExactlyInAnyOrder( |
||||||
|
"ConfigurationSecurityDesignRulesRepository", |
||||||
|
"ConfigurationSecurityDesignWayProfile", |
||||||
|
"ConfigurationFileLanguage", |
||||||
|
"ConfigFileSquidSensor", |
||||||
|
"File Suffixes"); |
||||||
|
} |
||||||
|
|
||||||
|
public static class MockedSonarRuntime implements SonarRuntime { |
||||||
|
|
||||||
|
@Override |
||||||
|
public Version getApiVersion() { |
||||||
|
return Version.create(9, 9); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public SonarProduct getProduct() { |
||||||
|
return SonarProduct.SONARQUBE; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public SonarQubeSide getSonarQubeSide() { |
||||||
|
return SonarQubeSide.SCANNER; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public SonarEdition getEdition() { |
||||||
|
return SonarEdition.COMMUNITY; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,34 @@ |
|||||||
|
/* |
||||||
|
* Copyright (c) 2023 - 2024. KeyWare.Co.Ltd All rights reserved. |
||||||
|
* 项目名称:信息安全性设计准则检查插件 |
||||||
|
* 项目描述:用于检查源代码的安全性设计准则的Sonarqube插件 |
||||||
|
* 版权说明:本软件属北京关键科技股份有限公司所有,在未获得北京关键科技股份有限公司正式授权情况下,任何企业和个人,不能获取、阅读、安装、传播本软件涉及的任何受知识产权保护的内容。 |
||||||
|
*/ |
||||||
|
package com.keyware.sonar.java.rules; |
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test; |
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat; |
||||||
|
|
||||||
|
/** |
||||||
|
* TODO JavaSecurityDesignRulesRepositoryTest |
||||||
|
* |
||||||
|
* @author GuoXin |
||||||
|
* @date 2024/1/6 |
||||||
|
*/ |
||||||
|
public class ConfigurationSecurityDesignRulesRepositoryTest { |
||||||
|
|
||||||
|
@Test |
||||||
|
void test() { |
||||||
|
// JavaSecurityDesignRulesRepository rulesDefinition = new JavaSecurityDesignRulesRepository(new JavaSecurityDesignRulesRepository.MockedSonarRuntime());
|
||||||
|
// RulesDefinition.Context context = new RulesDefinition.Context();
|
||||||
|
// rulesDefinition.define(context);
|
||||||
|
// RulesDefinition.Repository repository = context.repository(JavaSecurityDesignRulesRepository.REPOSITORY_KEY);
|
||||||
|
//
|
||||||
|
// assertThat(repository.name()).isEqualTo(JavaSecurityDesignRulesRepository.REPOSITORY_NAME);
|
||||||
|
// assertThat(repository.language()).isEqualTo("java");
|
||||||
|
// assertThat(repository.rules()).hasSize(RulesList.getJavaRules().size());
|
||||||
|
// assertThat(repository.rules().stream().filter(RulesDefinition.Rule::template)).isEmpty();
|
||||||
|
|
||||||
|
} |
||||||
|
} |
@ -0,0 +1,75 @@ |
|||||||
|
/* |
||||||
|
* Copyright (c) 2023 - 2024. KeyWare.Co.Ltd All rights reserved. |
||||||
|
* 项目名称:信息安全性设计准则检查插件 |
||||||
|
* 项目描述:用于检查源代码的安全性设计准则的Sonarqube插件 |
||||||
|
* 版权说明:本软件属北京关键科技股份有限公司所有,在未获得北京关键科技股份有限公司正式授权情况下,任何企业和个人,不能获取、阅读、安装、传播本软件涉及的任何受知识产权保护的内容。 |
||||||
|
*/ |
||||||
|
package com.keyware.sonar.java.utils; |
||||||
|
|
||||||
|
import java.io.File; |
||||||
|
import java.io.IOException; |
||||||
|
import java.nio.file.*; |
||||||
|
import java.nio.file.attribute.BasicFileAttributes; |
||||||
|
import java.util.ArrayList; |
||||||
|
import java.util.LinkedList; |
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
/** |
||||||
|
* Duplicates org.sonar.java.checks.verifier.FilesUtils to locate test jars within the custom-rules plugin |
||||||
|
*/ |
||||||
|
public class FilesUtils { |
||||||
|
|
||||||
|
private FilesUtils() { |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Default location of the jars/zips to be taken into account when performing the analysis. |
||||||
|
*/ |
||||||
|
private static final String DEFAULT_TEST_JARS_DIRECTORY = "target/test-jars"; |
||||||
|
|
||||||
|
public static List<File> getClassPath(String jarsDirectory) { |
||||||
|
List<File> classpath = new LinkedList<>(); |
||||||
|
Path testJars = Paths.get(jarsDirectory); |
||||||
|
if (testJars.toFile().exists()) { |
||||||
|
classpath = getFilesRecursively(testJars, "jar", "zip"); |
||||||
|
} else if (!DEFAULT_TEST_JARS_DIRECTORY.equals(jarsDirectory)) { |
||||||
|
throw new AssertionError("The directory to be used to extend class path does not exists (" |
||||||
|
+ testJars.toAbsolutePath() |
||||||
|
+ ")."); |
||||||
|
} |
||||||
|
classpath.add(new File("target/test-classes")); |
||||||
|
return classpath; |
||||||
|
} |
||||||
|
|
||||||
|
private static List<File> getFilesRecursively(Path root, String... extensions) { |
||||||
|
final List<File> files = new ArrayList<>(); |
||||||
|
|
||||||
|
FileVisitor<Path> visitor = new SimpleFileVisitor<Path>() { |
||||||
|
@Override |
||||||
|
public FileVisitResult visitFile(Path filePath, BasicFileAttributes attrs) { |
||||||
|
for (String extension : extensions) { |
||||||
|
if (filePath.toString().endsWith("." |
||||||
|
+ extension)) { |
||||||
|
files.add(filePath.toFile()); |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
return FileVisitResult.CONTINUE; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public FileVisitResult visitFileFailed(Path file, IOException exc) { |
||||||
|
return FileVisitResult.CONTINUE; |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
try { |
||||||
|
Files.walkFileTree(root, visitor); |
||||||
|
} catch (IOException e) { |
||||||
|
// we already ignore errors in the visitor
|
||||||
|
} |
||||||
|
|
||||||
|
return files; |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,113 @@ |
|||||||
|
/* |
||||||
|
* Copyright (c) 2023 - 2024. KeyWare.Co.Ltd All rights reserved. |
||||||
|
* 项目名称:信息安全性设计准则检查插件 |
||||||
|
* 项目描述:用于检查源代码的安全性设计准则的Sonarqube插件 |
||||||
|
* 版权说明:本软件属北京关键科技股份有限公司所有,在未获得北京关键科技股份有限公司正式授权情况下,任何企业和个人,不能获取、阅读、安装、传播本软件涉及的任何受知识产权保护的内容。 |
||||||
|
*/ |
||||||
|
|
||||||
|
package com.keyware.sonar.java.utils; |
||||||
|
|
||||||
|
import org.sonar.plugins.html.checks.HtmlIssue; |
||||||
|
import org.sonar.plugins.html.checks.PreciseHtmlIssue; |
||||||
|
|
||||||
|
import javax.annotation.Nullable; |
||||||
|
import java.util.*; |
||||||
|
|
||||||
|
/** |
||||||
|
* Html检查消息验证器 |
||||||
|
* |
||||||
|
* @author GuoXin |
||||||
|
* @date 2024/1/20 |
||||||
|
*/ |
||||||
|
public final class HtmlCheckMessagesVerifier { |
||||||
|
|
||||||
|
public static HtmlCheckMessagesVerifier verify(Collection<HtmlIssue> messages) { |
||||||
|
return new HtmlCheckMessagesVerifier(messages); |
||||||
|
} |
||||||
|
|
||||||
|
private final Iterator<HtmlIssue> iterator; |
||||||
|
private HtmlIssue current; |
||||||
|
|
||||||
|
private static final Comparator<HtmlIssue> ORDERING = (left, right) -> { |
||||||
|
if (Objects.equals(left.line(), right.line())) { |
||||||
|
return left.message().compareTo(right.message()); |
||||||
|
} else if (left.line() == null) { |
||||||
|
return -1; |
||||||
|
} else if (right.line() == null) { |
||||||
|
return 1; |
||||||
|
} else { |
||||||
|
return left.line().compareTo(right.line()); |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
private HtmlCheckMessagesVerifier(Collection<HtmlIssue> messages) { |
||||||
|
ArrayList<HtmlIssue> messagesList = new ArrayList<>(messages); |
||||||
|
messagesList.sort(ORDERING); |
||||||
|
iterator = messagesList.iterator(); |
||||||
|
} |
||||||
|
|
||||||
|
public HtmlCheckMessagesVerifier next() { |
||||||
|
if (!iterator.hasNext()) { |
||||||
|
throw new AssertionError("\nExpected violation"); |
||||||
|
} |
||||||
|
current = iterator.next(); |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
public void noMore() { |
||||||
|
if (iterator.hasNext()) { |
||||||
|
HtmlIssue next = iterator.next(); |
||||||
|
throw new AssertionError("\nNo more violations expected\ngot: at line " + next.line()); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private void checkStateOfCurrent() { |
||||||
|
if (current == null) { |
||||||
|
throw new IllegalStateException("Prior to this method you should call next()"); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public HtmlCheckMessagesVerifier atLine(@Nullable Integer expectedLine) { |
||||||
|
checkStateOfCurrent(); |
||||||
|
if (!Objects.equals(expectedLine, current.line())) { |
||||||
|
throw new AssertionError("\nExpected: " + expectedLine + "\ngot: " + current.line()); |
||||||
|
} |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
public HtmlCheckMessagesVerifier atLocation(int startLine, int startColumn, int endLine, int endColumn) { |
||||||
|
checkStateOfCurrent(); |
||||||
|
PreciseHtmlIssue preciseHtmlIssue = (PreciseHtmlIssue) current; |
||||||
|
if (!Objects.equals(startLine, current.line())) { |
||||||
|
throw new AssertionError("\nExpected: " + startLine + "\ngot: " + current.line()); |
||||||
|
} |
||||||
|
if (!Objects.equals(startColumn, preciseHtmlIssue.startColumn())) { |
||||||
|
throw new AssertionError("\nExpected: " + startColumn + "\ngot: " + preciseHtmlIssue.startColumn()); |
||||||
|
} |
||||||
|
if (!Objects.equals(endLine, preciseHtmlIssue.endLine())) { |
||||||
|
throw new AssertionError("\nExpected: " + endLine + "\ngot: " + preciseHtmlIssue.endLine()); |
||||||
|
} |
||||||
|
if (!Objects.equals(endColumn, preciseHtmlIssue.endColumn())) { |
||||||
|
throw new AssertionError("\nExpected: " + endColumn + "\ngot: " + preciseHtmlIssue.endColumn()); |
||||||
|
} |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
public HtmlCheckMessagesVerifier withMessage(String expectedMessage) { |
||||||
|
checkStateOfCurrent(); |
||||||
|
String actual = current.message(); |
||||||
|
if (!actual.equals(expectedMessage)) { |
||||||
|
throw new AssertionError("\nExpected: \"" + expectedMessage + "\"\ngot: \"" + actual + "\""); |
||||||
|
} |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
public HtmlCheckMessagesVerifier withCost(@Nullable Double expectedCost) { |
||||||
|
checkStateOfCurrent(); |
||||||
|
if (!Objects.equals(expectedCost, current.cost())) { |
||||||
|
throw new AssertionError("\nExpected: " + expectedCost + "\ngot: " + current.cost()); |
||||||
|
} |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,43 @@ |
|||||||
|
/* |
||||||
|
* Copyright (c) 2023 - 2024. KeyWare.Co.Ltd All rights reserved. |
||||||
|
* 项目名称:信息安全性设计准则检查插件 |
||||||
|
* 项目描述:用于检查源代码的安全性设计准则的Sonarqube插件 |
||||||
|
* 版权说明:本软件属北京关键科技股份有限公司所有,在未获得北京关键科技股份有限公司正式授权情况下,任何企业和个人,不能获取、阅读、安装、传播本软件涉及的任何受知识产权保护的内容。 |
||||||
|
*/ |
||||||
|
|
||||||
|
package com.keyware.sonar.java.utils; |
||||||
|
|
||||||
|
import org.junit.jupiter.api.extension.AfterEachCallback; |
||||||
|
import org.junit.jupiter.api.extension.ExtensionContext; |
||||||
|
import org.sonar.plugins.html.checks.HtmlIssue; |
||||||
|
|
||||||
|
import java.util.ArrayList; |
||||||
|
import java.util.Collection; |
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
/** |
||||||
|
* Html规则校验 |
||||||
|
* |
||||||
|
* @author GuoXin |
||||||
|
* @date 2024/1/20 |
||||||
|
*/ |
||||||
|
public class HtmlCheckMessagesVerifierRule implements AfterEachCallback { |
||||||
|
private final List<HtmlCheckMessagesVerifier> verifiers = new ArrayList<>(); |
||||||
|
|
||||||
|
public HtmlCheckMessagesVerifier verify(Collection<HtmlIssue> messages) { |
||||||
|
HtmlCheckMessagesVerifier verifier = HtmlCheckMessagesVerifier.verify(messages); |
||||||
|
verifiers.add(verifier); |
||||||
|
return verifier; |
||||||
|
} |
||||||
|
|
||||||
|
protected void verify() { |
||||||
|
for (HtmlCheckMessagesVerifier verifier : verifiers) { |
||||||
|
verifier.noMore(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void afterEach(ExtensionContext extensionContext) throws Exception { |
||||||
|
verify(); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,66 @@ |
|||||||
|
/* |
||||||
|
* Copyright (c) 2023 - 2024. KeyWare.Co.Ltd All rights reserved. |
||||||
|
* 项目名称:信息安全性设计准则检查插件 |
||||||
|
* 项目描述:用于检查源代码的安全性设计准则的Sonarqube插件 |
||||||
|
* 版权说明:本软件属北京关键科技股份有限公司所有,在未获得北京关键科技股份有限公司正式授权情况下,任何企业和个人,不能获取、阅读、安装、传播本软件涉及的任何受知识产权保护的内容。 |
||||||
|
*/ |
||||||
|
|
||||||
|
package com.keyware.sonar.java.utils; |
||||||
|
|
||||||
|
import org.sonar.api.batch.fs.InputFile; |
||||||
|
import org.sonar.api.batch.fs.internal.TestInputFileBuilder; |
||||||
|
import org.sonar.plugins.html.analyzers.ComplexityVisitor; |
||||||
|
import org.sonar.plugins.html.analyzers.PageCountLines; |
||||||
|
import org.sonar.plugins.html.api.HtmlConstants; |
||||||
|
import org.sonar.plugins.html.lex.PageLexer; |
||||||
|
import org.sonar.plugins.html.lex.VueLexer; |
||||||
|
import org.sonar.plugins.html.visitor.DefaultNodeVisitor; |
||||||
|
import org.sonar.plugins.html.visitor.HtmlAstScanner; |
||||||
|
import org.sonar.plugins.html.visitor.HtmlSourceCode; |
||||||
|
|
||||||
|
import java.io.File; |
||||||
|
import java.io.FileNotFoundException; |
||||||
|
import java.io.FileReader; |
||||||
|
import java.nio.charset.StandardCharsets; |
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
/** |
||||||
|
* Html测试工具类 |
||||||
|
* |
||||||
|
* @author GuoXin |
||||||
|
* @date 2024/1/20 |
||||||
|
*/ |
||||||
|
public class HtmlTestHelper { |
||||||
|
|
||||||
|
private HtmlTestHelper() { |
||||||
|
} |
||||||
|
|
||||||
|
public static HtmlSourceCode scan(File file, DefaultNodeVisitor visitor) { |
||||||
|
FileReader fileReader; |
||||||
|
try { |
||||||
|
fileReader = new FileReader(file); |
||||||
|
} catch (FileNotFoundException e) { |
||||||
|
throw new IllegalStateException(e); |
||||||
|
} |
||||||
|
|
||||||
|
HtmlSourceCode result = new HtmlSourceCode( |
||||||
|
new TestInputFileBuilder("key", file.getPath()) |
||||||
|
.setLanguage(HtmlConstants.LANGUAGE_KEY) |
||||||
|
.setType(InputFile.Type.MAIN) |
||||||
|
.setModuleBaseDir(new File(".").toPath()) |
||||||
|
.setCharset(StandardCharsets.UTF_8) |
||||||
|
.build() |
||||||
|
); |
||||||
|
|
||||||
|
HtmlAstScanner walker = new HtmlAstScanner(List.of(new PageCountLines(), new ComplexityVisitor())); |
||||||
|
PageLexer lexer = file.getName().endsWith(".vue") ? new VueLexer() : new PageLexer(); |
||||||
|
walker.addVisitor(visitor); |
||||||
|
walker.scan( |
||||||
|
lexer.parse(fileReader), |
||||||
|
result |
||||||
|
); |
||||||
|
|
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -1,30 +0,0 @@ |
|||||||
/* |
|
||||||
* 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,47 @@ |
|||||||
|
/* |
||||||
|
* Copyright (c) 2023 - 2024. KeyWare.Co.Ltd All rights reserved. |
||||||
|
* 项目名称:28所 C++ 信息安全性设计准则 |
||||||
|
* 项目描述:用于检查C++源代码的安全性设计准则的Sonarqube插件 |
||||||
|
* 版权说明:本软件属北京关键科技股份有限公司所有,在未获得北京关键科技股份有限公司正式授权情况下,任何企业和个人,不能获取、阅读、安装、传播本软件涉及的任何受知识产权保护的内容。 |
||||||
|
*/ |
||||||
|
package com.keyware.sonar.cxx; |
||||||
|
|
||||||
|
import com.keyware.sonar.cxx.rules.checkers.FlagLineRule; |
||||||
|
import com.keyware.sonar.cxx.rules.checkers.SqlVarNameChecker; |
||||||
|
import org.sonar.api.batch.fs.FilePredicates; |
||||||
|
import org.sonar.api.batch.fs.InputFile; |
||||||
|
import org.sonar.api.batch.rule.CheckFactory; |
||||||
|
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; |
||||||
|
|
||||||
|
public class FlagLineSensor implements Sensor { |
||||||
|
private final Checks<FlagLineRule> checks; |
||||||
|
|
||||||
|
|
||||||
|
public FlagLineSensor(CheckFactory checkFactory) { |
||||||
|
checks = checkFactory.create("cxx-security-design-rules"); |
||||||
|
checks.addAnnotatedChecks(SqlVarNameChecker.class); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void describe(SensorDescriptor descriptor) { |
||||||
|
//传感器名称
|
||||||
|
descriptor.name("FlagLine1Rule" + "sensor"); |
||||||
|
//传感器识别的语言
|
||||||
|
descriptor.onlyOnLanguages(CxxLanguage.KEY); |
||||||
|
//传感器扫描的规则库
|
||||||
|
descriptor.createIssuesForRuleRepository("cxx-security-design-rules"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void execute(SensorContext context) { |
||||||
|
FilePredicates p = context.fileSystem().predicates(); |
||||||
|
for (InputFile inputFile : context.fileSystem().inputFiles(p.hasLanguages(CxxLanguage.KEY))) { |
||||||
|
checks.all().forEach(check -> { |
||||||
|
check.execute(context, inputFile, checks.ruleKey(check)); |
||||||
|
}); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,31 @@ |
|||||||
|
/* |
||||||
|
* Copyright (c) 2023 - 2024. KeyWare.Co.Ltd All rights reserved. |
||||||
|
* 项目名称:28所 C++ 信息安全性设计准则 |
||||||
|
* 项目描述:用于检查C++源代码的安全性设计准则的Sonarqube插件 |
||||||
|
* 版权说明:本软件属北京关键科技股份有限公司所有,在未获得北京关键科技股份有限公司正式授权情况下,任何企业和个人,不能获取、阅读、安装、传播本软件涉及的任何受知识产权保护的内容。 |
||||||
|
*/ |
||||||
|
package com.keyware.sonar.cxx; |
||||||
|
|
||||||
|
import org.sonar.api.server.rule.RulesDefinition; |
||||||
|
|
||||||
|
public class LogRuleRepository implements RulesDefinition { |
||||||
|
private static final String REPOSITORY_NAME = "SonarQube"; |
||||||
|
|
||||||
|
@Override |
||||||
|
public void define(Context context) { |
||||||
|
// 创建规则仓库
|
||||||
|
NewRepository repository = context.createRepository("log", LogLanguage.KEY) |
||||||
|
.setName(REPOSITORY_NAME); |
||||||
|
|
||||||
|
// 创建新规则
|
||||||
|
|
||||||
|
NewRule errorRecoveryRule = repository.createRule("ParsingErrorRecovery"); |
||||||
|
errorRecoveryRule.setName("Parsing Error Recovery"); |
||||||
|
|
||||||
|
// 为另一个规则设置描述
|
||||||
|
errorRecoveryRule.setHtmlDescription("<p>This rule checks for parsing error recovery issues</p>"); |
||||||
|
|
||||||
|
// 完成规则创建
|
||||||
|
repository.done(); |
||||||
|
} |
||||||
|
} |
@ -1,265 +0,0 @@ |
|||||||
/* |
|
||||||
* 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,16 @@ |
|||||||
|
/* |
||||||
|
* Copyright (c) 2023 - 2024. KeyWare.Co.Ltd All rights reserved. |
||||||
|
* 项目名称:28所 C++ 信息安全性设计准则 |
||||||
|
* 项目描述:用于检查C++源代码的安全性设计准则的Sonarqube插件 |
||||||
|
* 版权说明:本软件属北京关键科技股份有限公司所有,在未获得北京关键科技股份有限公司正式授权情况下,任何企业和个人,不能获取、阅读、安装、传播本软件涉及的任何受知识产权保护的内容。 |
||||||
|
*/ |
||||||
|
package com.keyware.sonar.cxx.rules.checkers; |
||||||
|
|
||||||
|
import org.sonar.api.batch.fs.InputFile; |
||||||
|
import org.sonar.api.batch.sensor.SensorContext; |
||||||
|
import org.sonar.api.rule.RuleKey; |
||||||
|
|
||||||
|
public interface FlagLineRule { |
||||||
|
|
||||||
|
void execute(SensorContext sensorContext, InputFile file, RuleKey ruleKey); |
||||||
|
} |
@ -0,0 +1,78 @@ |
|||||||
|
/* |
||||||
|
* Copyright (c) 2023 - 2024. KeyWare.Co.Ltd All rights reserved. |
||||||
|
* 项目名称:28所 C++ 信息安全性设计准则 |
||||||
|
* 项目描述:用于检查C++源代码的安全性设计准则的Sonarqube插件 |
||||||
|
* 版权说明:本软件属北京关键科技股份有限公司所有,在未获得北京关键科技股份有限公司正式授权情况下,任何企业和个人,不能获取、阅读、安装、传播本软件涉及的任何受知识产权保护的内容。 |
||||||
|
*/ |
||||||
|
package com.keyware.sonar.cxx.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.Priority; |
||||||
|
import org.sonar.check.Rule; |
||||||
|
import org.sonar.cxx.squidbridge.annotations.ActivatedByDefault; |
||||||
|
import org.sonar.cxx.squidbridge.annotations.SqaleConstantRemediation; |
||||||
|
|
||||||
|
import java.io.IOException; |
||||||
|
import java.nio.charset.StandardCharsets; |
||||||
|
import java.util.Scanner; |
||||||
|
|
||||||
|
/** |
||||||
|
* C++规则检查器的实现示例 |
||||||
|
* |
||||||
|
* @author GuoXin |
||||||
|
* @date 2024/1/6 |
||||||
|
*/ |
||||||
|
@Rule(key = "FlagLine1Rule", name = "sql注入", description = "sql注入有一定风险", priority = Priority.INFO, tags = {"28suo"}) |
||||||
|
@ActivatedByDefault |
||||||
|
@SqaleConstantRemediation("5min") |
||||||
|
public class SqlVarNameChecker implements FlagLineRule { |
||||||
|
|
||||||
|
@Override |
||||||
|
public void execute(SensorContext sensorContext, InputFile file, RuleKey ruleKey) { |
||||||
|
try (Scanner scanner = new Scanner(file.inputStream(), StandardCharsets.UTF_8.name())) { |
||||||
|
int lineNumber = 1; |
||||||
|
while (scanner.hasNextLine()) { |
||||||
|
String line = scanner.nextLine(); |
||||||
|
if (line.contains("= '") || line.contains("OR 1=1") || line.contains("='") |
||||||
|
|| line.contains("DROP TABLE") || line.contains("' OR 'a'='a") || line.contains("'; DROP TABLE users; --") |
||||||
|
|| line.contains("'; EXEC xp_cmdshell 'dir'") || line.contains("' OR username LIKE '%") || line.contains("' AND SLEEP(5)") |
||||||
|
|| line.contains("= \\'' +") || line.contains("= ?")) { // 根据特定的关键词或模式匹配来定位 SQL 注入
|
||||||
|
NewIssue newIssue = sensorContext.newIssue(); |
||||||
|
newIssue |
||||||
|
.forRule(ruleKey) |
||||||
|
.at(newIssue.newLocation() |
||||||
|
.on(file) |
||||||
|
.at(file.selectLine(lineNumber))) |
||||||
|
.save(); |
||||||
|
} |
||||||
|
lineNumber++; |
||||||
|
} |
||||||
|
} catch (IOException e) { |
||||||
|
throw new RuntimeException(e); |
||||||
|
} |
||||||
|
} |
||||||
|
/* |
||||||
|
@Override |
||||||
|
public void visitNode(AstNode node) { |
||||||
|
File file = getContext().getFile(); |
||||||
|
System.out.println("文件路径: " + file.getAbsolutePath()); |
||||||
|
try (BufferedReader reader = new BufferedReader(new FileReader(file))) { |
||||||
|
String line; |
||||||
|
int lineNumber = 0; |
||||||
|
while ((line = reader.readLine()) != null) { |
||||||
|
lineNumber++; |
||||||
|
if (line.contains("= '") || line.contains("OR 1=1") || line.contains("='") |
||||||
|
|| line.contains("DROP TABLE") || line.contains("' OR 'a'='a") || line.contains("'; DROP TABLE users; --") |
||||||
|
|| line.contains("'; EXEC xp_cmdshell 'dir'") || line.contains("' OR username LIKE '%") || line.contains("' AND SLEEP(5)") |
||||||
|
|| line.contains("= \\'' +") || line.contains("= ?")) { |
||||||
|
getContext().createLineViolation(ABCVarNameChecker.this, "sql 注入有一定风险", lineNumber); |
||||||
|
} |
||||||
|
} |
||||||
|
} catch (IOException e) { |
||||||
|
e.printStackTrace(); |
||||||
|
} |
||||||
|
}*/ |
||||||
|
} |
@ -1,72 +0,0 @@ |
|||||||
/* |
|
||||||
* 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); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
} |
|
@ -1,276 +0,0 @@ |
|||||||
/* |
|
||||||
* Copyright (c) 2023 - 2024. KeyWare.Co.Ltd All rights reserved. |
|
||||||
* 项目名称:信息安全性设计准则检查插件 |
|
||||||
* 项目描述:用于检查源代码的安全性设计准则的Sonarqube插件 |
|
||||||
* 版权说明:本软件属北京关键科技股份有限公司所有,在未获得北京关键科技股份有限公司正式授权情况下,任何企业和个人,不能获取、阅读、安装、传播本软件涉及的任何受知识产权保护的内容。 |
|
||||||
*/ |
|
||||||
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; |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* 通过用户名口令、数据证书等其他手段对用户身份进行验证。 |
|
||||||
* |
|
||||||
* @author WuHaoYang |
|
||||||
* @date 2024/1/22 |
|
||||||
*/ |
|
||||||
@Rule(key = "ConfigurationFileChecker") |
|
||||||
public class ConfigurationFileChecker implements ConfigCheck{ |
|
||||||
|
|
||||||
|
|
||||||
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()); |
|
||||||
System.out.println("---------------properties文件路径----------------"+file); |
|
||||||
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(); |
|
||||||
|
|
||||||
// 构建目录路径
|
|
||||||
System.out.println("---------------ini文件路径----------------"+file1); |
|
||||||
|
|
||||||
int lineNum = 1; |
|
||||||
Properties properties = new Properties(); |
|
||||||
|
|
||||||
try (FileInputStream fileInput = new FileInputStream(file1)) { |
|
||||||
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(); |
|
||||||
|
|
||||||
// 构建目录路径
|
|
||||||
System.out.println("---------------conf文件路径----------------"+file1); |
|
||||||
|
|
||||||
|
|
||||||
int lineNum = 1; |
|
||||||
Properties prop = new Properties(); |
|
||||||
InputStream input = null; |
|
||||||
|
|
||||||
try { |
|
||||||
input = new FileInputStream(file1); |
|
||||||
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++; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (filename.endsWith(".xml")){ |
|
||||||
// 获取当前输入文件的绝对路径
|
|
||||||
File file1 = inputFile.file(); |
|
||||||
File absoluteFile = file1.getAbsoluteFile(); |
|
||||||
|
|
||||||
// 构建目录路径
|
|
||||||
File dir = new File(String.valueOf(absoluteFile)).getParentFile(); |
|
||||||
System.out.println("---------------xml文件路径----------------"+file1); |
|
||||||
File xmlFile = new File(dir, filename); |
|
||||||
processXML(xmlFile); |
|
||||||
int lineNum = 1; |
|
||||||
NewIssue newIssue = context.newIssue(); |
|
||||||
newIssue |
|
||||||
.forRule(ruleKey) |
|
||||||
.at(newIssue.newLocation() |
|
||||||
.on(inputFile) |
|
||||||
.at(inputFile.selectLine(lineNum))) |
|
||||||
.save(); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
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文件路径----------------"+file1); |
|
||||||
ObjectMapper mapper = new ObjectMapper(); |
|
||||||
JsonNode rootNode = mapper.readTree(file1); |
|
||||||
extractPassword(rootNode); |
|
||||||
int lineNum = 1; |
|
||||||
NewIssue newIssue = context.newIssue(); |
|
||||||
newIssue |
|
||||||
.forRule(ruleKey) |
|
||||||
.at(newIssue.newLocation() |
|
||||||
.on(inputFile) |
|
||||||
.at(inputFile.selectLine(lineNum))) |
|
||||||
.save(); |
|
||||||
|
|
||||||
} 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文件路径----------------"+file1); |
|
||||||
Yaml yaml = new Yaml(); |
|
||||||
try (FileInputStream fis = new FileInputStream(file1)) { |
|
||||||
Map<String, Object> obj = yaml.load(fis); |
|
||||||
if (obj != null){ |
|
||||||
String password = searchPassword(obj); |
|
||||||
if (password != null) { |
|
||||||
System.out.println("password="+password); |
|
||||||
int lineNum = 1; |
|
||||||
NewIssue newIssue = context.newIssue(); |
|
||||||
newIssue |
|
||||||
.forRule(ruleKey) |
|
||||||
.at(newIssue.newLocation() |
|
||||||
.on(inputFile) |
|
||||||
.at(inputFile.selectLine(lineNum))) |
|
||||||
.save(); |
|
||||||
} |
|
||||||
} |
|
||||||
} 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; |
|
||||||
} |
|
||||||
} |
|
Loading…
Reference in new issue