Java

-verbose:class オプションを使ってLog4j利用の有無、Log4jを利用しているクラスを調査する

Log4jの脆弱性

Log4jの脆弱性が騒ぎになっています。権限の昇格はないものの、Javaプロセスを動かしているユーザーの権限で出来ることは何でも出来てしまい、しかも攻撃も容易なため今すぐに対処すべきです。
条件により脆弱性が問題とならなかったり、システムプロパティの設定により問題を回避することが出来たりしますが、Log4jを利用しているシステムでは原則、最新リリースであるLog4j 2.15.0(またはそれ以降)にアップデートするのが良いでしょう。

なおLog4j 2.XはLog4j2と呼ばれるバージョンです。Log4j 1.xはかなり昔にEOLを迎えているのでバージョンアップしましょう。

Log4jを利用しているか分からない場合

Log4jをプロジェクトで利用しているかどうか分からない場合は、ひとまず問題を回避できるシステムプロパティ log4j2.formatMsgNoLookups または環境変数 LOG4J_FORMAT_MSG_NO_LOOKUPS をtrueに設定してアプリケーションを再起動しましょう。

システムプロパティは -Dlog4j2.formatMsgNoLookups=true をJavaを呼びだすコマンドに付加することで、環境変数は起動するシェルまたはバッチファイルで設定できます。

Log4jを利用しているかどうか確認する方法

Log4j 2.xを利用しているかどうかは、pom.xmlやbuild.gradleを見れば分かる場合もありますが、依存しているライブラリがその先で依存していたり、動的にロードしていたりしてプロジェクトの設定からは利用していることが分からない場合があります。

今回問題を引き起こしているのは org.apache.logging.log4j.core.lookup.JndiLookup というクラスです。このクラスや、Log4jを利用する際の起点となるorg.apache.logging.log4j.LogManager、org.apache.logging.log4j.Loggerがロードされているかどうかを調べることでLog4jを利用しているかどうか確認することができます。

どのクラスがロードされているかはJVMに -verbose:class という起動オプションをつけることで確認できます。厳密にはこのオプションによりアプリケーションの起動パフォーマンスがわずかに劣化しますが、今はパフォーマンスよりもセキュリティに焦点をあてるべきです。

Log4jを利用していると次のようなパターンのメッセージが標準出力に記録されます。

[0.107s][info][class,load] org.apache.logging.log4j.core.lookup.JndiLookup source: file:/Users/yusuke/.m2/repository/org/apache/logging/log4j/log4j-core/2.15.0/log4j-core-2.15.0.jar
[0.056s][info][class,load] org.apache.logging.log4j.LogManager source: file:/Users/yusuke/.m2/repository/org/apache/logging/log4j/log4j-api/2.15.0/log4j-api-2.15.0.jar
[0.057s][info][class,load] org.apache.logging.log4j.Logger source: file:/Users/yusuke/.m2/repository/org/apache/logging/log4j/log4j-api/2.15.0/log4j-api-2.15.0.jar

Log4jを呼びだしているクラスの突き止め方

LogManagerやLoggerをロードしている箇所を突き止めたら一行ずつ行を遡ります。java.*やjdk.*といったJavaの標準APIのクラス*以外*をロードしている行があれば、それがLog4jを呼びだしているクラスになります。

次の例だとLogManagerを起点に遡って最初のjava.*/jdk.*以外のクラスであるone.cafebabe.Log4JTestがLog4jを呼びだしていることが分かります。