SonarQube Javaカスタムルール作成共有
今日の大部分の会社はすべて自分の業務コードに対して安全性の監査を行う需要があって、業務コードの安全性を保証して、同時にコード監査はSDLの中で重要な一環として、効果的に業務のCIAを保証することができます.しかし、人工監査には深刻な性能ボトルネックがあり、コードスキャナの単純な使用も効果的ではなく、誤報の問題が多い.現在の良い方法:ビジネス、カスタムルール、両者の優位性を組み合わせます.しかし、ネット上ではこの方面についての紹介が少なく、この文章が需要のある学生を助けることができることを望んでいます.選択したスキャンはSonarQubeで、このスキャナーはオープンソーススキャナーの中で比較的に優れており、豊富な画像化インタフェースと強力な文法解析能力を持っている.
準備作業
sonar-javaプラグインのキー構造
JAva-checksモジュール:最も重要なJAVAスキャン規則セットjava-frontendモジュールを含む:このモジュールはJAVA構文解析クラスを提供し、このプラグインの基礎である
1つのルールの必要構成
まずjava-checkのスキャンルールを例として使用し、ルールの作成と登録方法について説明します.ルールパスは以下の通りです.org.sonar.java.checks.spring.RequestMappingMethodPublicCheck
まずルール本体を見てください.
package org.sonar.java.checks.spring;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.sonar.check.Rule;
import org.sonar.plugins.java.api.IssuableSubscriptionVisitor;
import org.sonar.plugins.java.api.semantic.Symbol;
import org.sonar.plugins.java.api.tree.MethodTree;
import org.sonar.plugins.java.api.tree.Tree;
@Rule(key = "S3751")
public class RequestMappingMethodPublicCheck extends IssuableSubscriptionVisitor {
@Override
public List nodesToVisit() {
return Collections.singletonList(Tree.Kind.METHOD);
}
private static final List CONTROLLER_ANNOTATIONS = Arrays.asList(
"org.springframework.stereotype.Controller",
"org.springframework.web.bind.annotation.RestController"
);
private static final List REQUEST_ANNOTATIONS = Arrays.asList(
"org.springframework.web.bind.annotation.RequestMapping",
"org.springframework.web.bind.annotation.GetMapping",
"org.springframework.web.bind.annotation.PostMapping",
"org.springframework.web.bind.annotation.PutMapping",
"org.springframework.web.bind.annotation.DeleteMapping",
"org.springframework.web.bind.annotation.PatchMapping"
);
@Override
public void visitNode(Tree tree) {
if (!hasSemantic()) {
return;
}
MethodTree methodTree = (MethodTree) tree;
Symbol.MethodSymbol methodSymbol = methodTree.symbol();
if (isClassController(methodSymbol)
&& isRequestMappingAnnotated(methodSymbol)
&& !methodSymbol.isPublic()) {
reportIssue(methodTree.simpleName(), "Make this method \"public\".");
}
}
private static boolean isClassController(Symbol.MethodSymbol methodSymbol) {
return CONTROLLER_ANNOTATIONS.stream().anyMatch(methodSymbol.owner().metadata()::isAnnotatedWith);
}
private static boolean isRequestMappingAnnotated(Symbol.MethodSymbol methodSymbol) {
return REQUEST_ANNOTATIONS.stream().anyMatch(methodSymbol.metadata()::isAnnotatedWith);
}
}
このルールの核心はvisitNodeであり、このメソッドを書き換えることで、スキャンタスクの実行時に自動的に呼び出されるスキャンされたJavaファイルの構文ツリーを巡ります.
このルールの実行プロセス:
ルール定義ファイルS 3751_java.json
S 3751はこのスキャンルールのKeyであり、ルールファイルに@Rule(key="S 3751")で定義される
{
"title": "\"@RequestMapping\" methods should be \"public\"",
"type": "VULNERABILITY",
"status": "ready",
"remediation": {
"func": "Constant\/Issue",
"constantCost": "2min"
},
"tags": [
"spring",
"owasp-a6"
],
"standards": [
"OWASP Top Ten"
],
"defaultSeverity": "Blocker",
"ruleSpecification": "RSPEC-3751",
"sqKey": "S3751",
"scope": "Main",
"securityStandards": {
"OWASP": [
"A6"
]
}
}
type:VULNERABILITY、BUG SECURITYを含むルールのタイプです.HOTSPOT、CODE_SMELLなど.constantCost:代表がこの問題を解決するにはどのくらいの時間がかかりますか.scope:All、Main、Testなど、スキャンするアイテムの仕様を定義します.
ルール詳細記述ファイルS 3751_java.html
ルール詳細は、SonarQube Webエンドルール詳細ページに表示されます
A method with a @RequestMapping
annotation part of a class annotated with @Controller
(directly or indirectly through a
meta annotation - @RestController
from Spring Boot is a good example) will be called to handle matching web requests. That will happen
even if the method is private
, because Spring invokes such methods via reflection, without checking visibility.
So marking a sensitive method private
may seem like a good way to control how such code is called. Unfortunately, not all Spring
frameworks ignore visibility in this way. For instance, if you've tried to control web access to your sensitive, private
,
@RequestMapping
method by marking it @Secured
... it will still be called, whether or not the user is authorized to access
it. That's because AOP proxies are not applied to non-public methods.
In addition to @RequestMapping
, this rule also considers the annotations introduced in Spring Framework 4.3: @GetMapping
,
@PostMapping
, @PutMapping
, @DeleteMapping
, @PatchMapping
.
Noncompliant Code Example
@RequestMapping("/greet", method = GET)
private String greet(String greetee) { // Noncompliant
Compliant Solution
@RequestMapping("/greet", method = GET)
public String greet(String greetee) {
See OWASP Top 10 2017 Category A6 - Security Misconfiguration どちらのファイルもsonar-java/java-checks/src/main/resources/org/sonar/l 10 n/java/rules/squid/ディレクトリの にあり、カスタムルールjsonとhtmlファイルもこのディレクトリの に します.ファイル はKEY_java.json KEY_java.html.KEYルールで@Rule を する
テストファイル
いルールを するには くのテストが になります.TDD(テストドライバ )によって いルールを くのに ちます.この のルールのテストファイル:org.sonar.java.checks.spring.R e q u s t M eppingMethodPublicCheckTestpackage org.sonar.java.checks.spring;
import org.junit.Test;
import org.sonar.java.checks.verifier.JavaCheckVerifier;
public class RequestMappingMethodPublicCheckTest {
@Test
public void test() {
JavaCheckVerifier.verify("src/test/files/checks/spring/RequestMappingMethodPublicCheck.java", new RequestMappingMethodPublicCheck());
JavaCheckVerifier.verifyNoIssueWithoutSemantic("src/test/files/checks/spring/RequestMappingMethodPublicCheck.java",
new RequestMappingMethodPublicCheck());
}
}
JavaCheckVerifierクラスで されているメソッドを して、ルールスキャンファイルを します.
ルール
org.sonar.java.checks.CheckListに し、addメソッドを して するルールを
カスタムサンプルの
Struts 2 S 2-057 :スキャン pom.xmlでS 2-057 バージョンを むstruts 2 を するかどうかpackage org.sonar.java.checks.xml.maven;
import org.sonar.java.checks.xml.maven.helpers.MavenDependencyCollector;
import org.sonar.java.xml.maven.PomCheck;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import org.apache.commons.lang.StringUtils;
import org.sonar.check.Priority;
import org.sonar.check.Rule;
import org.sonar.java.xml.maven.PomCheckContext;
import org.sonar.maven.model.LocatedAttribute;
import org.sonar.maven.model.maven2.Dependency;
import javax.annotation.Nullable;
import java.util.List;
@Rule(key = "Struts2_S2_057Check")
public class Struts2_S2_057Check implements PomCheck {
@Override
public void scanFile(PomCheckContext context) {
List dependencies = new MavenDependencyCollector(context.getMavenProject()).allDependencies();
for (Dependency dependency : dependencies) {
LocatedAttribute artifactId = dependency.getArtifactId();
LocatedAttribute version = dependency.getVersion();
if (version != null && artifactId != null && "struts2-core".equalsIgnoreCase(artifactId.getValue()) && !strutsVerCompare(version.getValue())) {
String message = " Struts2 ";
List secondaries = getSecondary(version);
int line = version.startLocation().line();
context.reportIssue(this, line, message, secondaries);
}
}
}
private static List getSecondary(@Nullable LocatedAttribute systemPath) {
if (systemPath != null && StringUtils.isNotBlank(systemPath.getValue())) {
return Lists.newArrayList(new PomCheckContext.Location("configure check", systemPath));
}
return ImmutableList.of();
}
private static boolean strutsVerCompare(String version){
String StrutsVersion1 = "2.3.35";
String StrutsVersion2 = "2.5.17";
String[] versionArray1 = version.split("\\.");
if(versionArray1[1].equalsIgnoreCase("3")){
if(compareVersion(StrutsVersion1, version) > 0){
return false;
}
}
if(versionArray1[1].equalsIgnoreCase("5")){
if(compareVersion(StrutsVersion2, version) > 0){
return false;
}
}
return true;
}
private static int compareVersion(String version1, String version2){
String[] versionArray1 = version1.split("\\.");
String[] versionArray2 = version2.split("\\.");
int idx = 0;
int minLength = Math.min(versionArray1.length, versionArray2.length);
int diff = 0;
while (idx < minLength
&& (diff = versionArray1[idx].length() - versionArray2[idx].length()) == 0
&& (diff = versionArray1[idx].compareTo(versionArray2[idx])) == 0) {
++idx;
}
diff = (diff != 0) ? diff : versionArray1.length - versionArray2.length;
return diff;
}
}
ルールの :
まず、いくつかのキーを てみましょう. @Rule(key = "Struts2_S2_057Check")
この は の のKey を する. implements PomCheck
public void scanFile(PomCheckContext context)
この はPomCheckクラスを し、scanFileを き えることで、プラグインとスキャナが にPomを する.xmlファイルは、 のpomファイル ツリーを に します. strutsVerCompare
どのバージョンのStruts 2 を するために される その sonar-java/java-checks/src/main/resources/org/sonar/l10n/java/rules/squid/
でStruts 2_を S2_057Check_java.jsonとStruts 2_S2_057Check_java.htmlの2つのファイルは、 のルールを にして することができます. にCheckListに します.
プラグインコンパイルmvn clean package -Dlicense.skip=true
-Dlicense.skip=true チェックをスキップ
する のある
コンパイル にmaven 2 クラスが つからないことを すプロンプトが され、sonar-java/java-maven-model/target/generated-sourcesディレクトリをGenerated Sources Rootに します.