🧪

OWASP Dependency-Check を使ってMavenの依存ライブラリの脆弱性を確認する

2021/12/11に公開

こちらはJava Advent Calendar 2021の11日目です。

はじめに

「Apache Log4j」ライブラリに致命的なリモートコード実行の脆弱性が発見され現在絶賛対応中の方もいらっしゃるかと思います。
https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-44228
https://qiita.com/su-guru/items/284cc90b825e608cf432

ここで重要になってくるのが影響調査には自分たちの改修しているコード本体だけではなく、OSSの依存ライブラリも含まれることです。log4j2は超広範囲に利用されていますから、逆にJavaのコードは潜在的に対象、くら言ってしまっても良いですが、もう少しマイナーなライブラリだとそもそも対象となるコードを探すのが大変です。pom.xmlをgrepしただけでは見つけれないですから。

この手の依存性チェックをするツールはありそうだと思ってたけど、特に今まで使った事はなかったので今回はMavenプラグインのOWASP Dependency-Checkを試してみました。

今回サンプルに利用舌コードは下記から参照できます。
https://github.com/koduki/example-owasp-dependency-check

OWASP Dependency-Checkとは?

OWASP(Open Web Application Security)は主にWebアプリケーションをターゲットとしたセキュリティの団体です。有名な成果物に脅威のランキングであるOWASP Top 10や無料のWebアプリケーションスキャナであるOWASP ZAPなどがあります。こういった成果物の一つが利用しているライブラリの脆弱性をチェックするOWASP Dependency-Checkです。
https://owasp.org/www-project-dependency-check/

NVD (National Vulnerability Database) Common Vulnerability and Exposure (CVE)等を脆弱性情報のインプットにしているので適切に最新の脅威に追従できます。

多くの実行環境があり、CLI/Dockerで実行することもできますし、Maven/Gradle/SBTのようなビルドツールに設定することも、JenkinsやCircleCIあるいはSonarQubeといったCIツールやコード解析ツールに統合することもできます。今回はMavenプラグインを利用しました。

OWASP Dependency-Check Mavenで脆弱性のあるライブラリを検知する

それでは使ってみましょう。以下のようにpom.xmlにdependency checkでのプラグインを追加します。また、まずは脆弱性のあるライブラリとしてlog4j:2.14.0を直接参照しています。

    <build>
      <plugins>
        <plugin>
            <groupId>org.owasp</groupId>
            <artifactId>dependency-check-maven</artifactId>
            <executions>
            <execution>
              <goals>
                <goal>check</goal>
              </goals>
            </execution>
          </executions>
        </plugin>
      </plugins>
    </build>
    <dependencies>
        <!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-core -->
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-core</artifactId>
            <version>2.14.0</version>
        </dependency>
    </dependencies>
</project>

Java側は例えばこんな感じ。

public static void main(String[] args) {
    var logger = LogManager.getLogger();        
    logger.error("Hello Log4j2");
}

以下のコマンドでcheckを実行します。

$ mvn clean dependency-check:check
〜 中略 〜
[INFO] Writing report to: /home/pascalm3/example-java-dependency/example-app/target/dependency-check-report.html
[WARNING]

One or more dependencies were identified with known vulnerabilities in example-java-dependency:

log4j-core-2.14.0.jar (pkg:maven/org.apache.logging.log4j/log4j-core@2.14.0, cpe:2.3:a:apache:log4j:2.14.0:*:*:*:*:*:*:*) : CVE-2021-44228

See the dependency-check report for more details.
〜 中略 〜
[INFO] BUILD SUCCESS

まさに先日レポートされたlog4jの脆弱性もバッチ理指摘されましたね。CVEの番号も出ています。更に詳しい情報がdependency-check-report.htmlに出力されているのでこちらを見ることもできます。

これで自分が使っているプロダクトで使っているライブラリの脆弱性を検知することができます。

依存ライブラリが脆弱性のあるライブラリを更に参照している場合

上記のサンプルは自身のpom.xmlに直接参照しているケースでしたが、探すのが大変なのは依存ライブラリがさらに依存してるライブラリに脆弱性があるケースです。今回のlog4jの問題とかはこちらに当てはまるケースも多いでしょう。というわけで、以下のようにMyLibという別のライブラリを作り、そちらにのみ脆弱性のあるライブラリを入れてみます。

まず、以下のようにライブラリを作り、こちらに脆弱性のあるライブラリを参照させてみます。これをmvn clean installあたりでローカルに配置します。

<artifactId>example-java-dependency-lib</artifactId>
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
<name>example-java-dependency-lib</name>
<url>http://maven.apache.org</url>
<properties>
    <maven.compiler.source>11</maven.compiler.source>
    <maven.compiler.target>11</maven.compiler.target>
</properties>
<dependencies>
    <!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-core -->
    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-core</artifactId>
        <version>2.14.0</version>
    </dependency>
</dependencies>

メインのアプリ側のpom.xmlは以下のようにlog4jの依存を排除しておきます。そして依存に先程作ったライブラリを追加します。これでOSSなどの外部がライブラリを参照しているのと同じ状態がつくれました。

<artifactId>example-java-dependency</artifactId>
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
<name>example-java-dependency</name>
<url>http://maven.apache.org</url>
<properties>
    <maven.compiler.source>11</maven.compiler.source>
    <maven.compiler.target>11</maven.compiler.target>
</properties>
<build>
    <plugins>
    <plugin>
        <groupId>org.owasp</groupId>
        <artifactId>dependency-check-maven</artifactId>
        <executions>
        <execution>
            <goals>
            <goal>check</goal>
            </goals>
        </execution>
        </executions>
    </plugin>
    </plugins>
</build>
<dependencies>
    <dependency>
        <groupId>dev.nklab.example</groupId>
        <artifactId>example-java-dependency-lib</artifactId>
        <version>1.0-SNAPSHOT</version>
    </dependency>
</dependencies>

アプリ側のコードは以下のようになります。

public static void main(String[] args) {
    MyLib.log("Hello Dependency");
}

mvn clean dependency-check:checkを実行すると無事?依存ライブラリの先にしかない脆弱性のあるライブラリを検知できました。

ただ特にどのライブラリの先に脆弱性のあるライブラリがあるかとかは判定できなさそうです。オプションで変えれるかもしれないですが、特に必要ない気もしますし問題はないかと。

まとめ

Mavenの依存ツリーを辿って脆弱性のあるライブラリを検知するOWASP Dependency-Checkを紹介しました。

他にもあると思いますが、結構手軽に導入できるのでOWAP Dependency-Checkは中々便利そうです。実際にビルドパイプラインに組み込むなら自分はSonarQube側に入れるかな? 今度試してみたいです。またGitHubを筆頭に最近のコードリポジトリやMavenリポジトリは賢いのでこのあたりを自動的に検知してレポートをしてくれます。実際、Github Botから大量にlog4jのバージョンが古いと怒られていますしw ゼロデイはまだしも新規コードでも以前のバージョンをそのまま使って古いバージョンを広げてしまうことはあるので、このあたりを活用してなくしていきたいですね。

とはいえ、検知してすべて対処するのは難しいので実際はCriticalだけは即時対応とかいくつかのルールを整備する必要があり、そちらも大事になってきます。ここら辺のプロセス作りが安全なコードへの第一歩。

それではHappy Hacking!

Discussion