Spring Bootのセキュリティ脆弱性への対処
2023年11月29日
0 分で読めますソフトウェア開発では、依存関係の管理が、安全で堅牢なアプリケーションを構築するうえで欠かせません。Java開発者に人気のSpring Bootを使えばアプリケーションを簡単に構築できますが、それだけでは十分ではありません。依存関係を適切に管理することは、Spring Bootプロジェクトを円滑に稼働させ、絶えず進化する脅威に対する耐性を保つために重要です。
Spring Bootの依存関係管理で特に重要なのが、セキュリティです。ソフトウェアの脆弱性は頻繁に発見されます。プロジェクトの依存関係を最新の状態に保つことは、デジタルセキュリティの鎧を身に着けるようなものです。古い依存関係は、脅威を招き入れる鍵のかかっていないドアのようなもの。そうした事態は避けたいものです。
Spring Bootの脆弱性を見つける
ソフトウェア構成分析(SCA)ツールは、開発者にとって非常に役立ちます。依存関係の管理、セキュリティ脆弱性への対処、ライセンス問題の把握、ソフトウェアプロジェクトのコンプライアンス確保を簡単に実現できます。SCAツールとしてSnyk Open Sourceを使えば、Spring Bootのパッケージに脆弱性が含まれているかどうかを簡単に確認できます。
今回のサンプルプロジェクトでは、複数の脆弱性が見つかりました。1つ目は、`netty-codec-http2`に存在する深刻度の高いセキュリティ問題です。以下に示すように、これは`spring-boot-start-webflux`によって取り込まれる推移的依存関係です。

次に取り上げるのは、`snakeyaml`パッケージを介して取り込まれる、深刻度が中程度の任意コード実行の脆弱性です。これも推移的依存関係で、今回は`spring-boot-starter-security`によって取り込まれます。

今日は個々の脆弱性の詳細には触れませんが、`snakeyaml`の問題については、詳しく解説したブログ記事をご覧ください。ここでは、問題の解決と最適な対処方法の実践に焦点を当てましょう。
Spring Bootアプリケーションの脆弱なパッケージを修正する
1つ目の脆弱性には、明確な修正方法が提示されています。私のアプリケーションはSpring Boot 2.7.16をベースにしているため、`spring-boot-starter-webflux`もバージョン2.7.16です。
Webflux starterを2.7.17に更新すれば、問題を修正できます。更新する方法はいくつかありま
すが、すべてが推奨されるわけではありません。
通常、Spring Bootのマニフェストは次のようになります。
Maven:
Gradle:
Spring Boot starterを更新する
個々の`spring-boot-starters`のバージョン番号は、`spring-boot-starter-parent`(Maven)またはGradleの`org.springframework.boot`プラグインから決まります。
これは、これらのstarterパッケージがすべて同じSpringリリースに属し、一体としてテストされているためです。
プロジェクトで見つかった1つ目の脆弱性を見ると、深刻度の高いセキュリティ脆弱性を解消するため、`spring-boot-starter-webflux`をバージョン2.7.17に更新するよう提案されています。つまり、Webfluxパッケージだけを修正すればよいように見えます。以下のように特定のバージョンを指定すれば更新できます。
Maven:
Gradle:
ただし、ここでいったん立ち止まってください。これは推奨される解決方法ではありません。親のバージョンではなく、特定のバージョン2.7.17が使われます。パッチリリースなので動作する可能性はありますが、最善かつ最も安全な方法とは言えません。セマンティックバージョニングではAPIの互換性が保証されないため、正常に動くとは限らないからです。さらに重要なのは、Spring Bootの新しいリリースがすでに公開されている可能性があることです。
先ほど、これらのstarterは一緒に使うものだと説明しました。そのため、最善の方法はSpring Bootのディストリビューション全体を2.7.17に更新することです。APIに影響し、連携がうまくいかなくなる可能性があるマイナーリリースやメジャーリリースでは、特に重要です。この例では、個々のstarterではなく、親(Maven)またはプラグイン(Gradle)を更新してください。
Maven:
Gradle:
できる限り、Spring Boot全体を適切な最新バージョンに更新することをお勧めします。適切なバージョンを確認するには、https://start.spring.io にアクセスしてください。

推移的依存関係を更新する
2つ目の問題について、Snykはアプリケーションに明確な修正方法がないことを検出しました。現時点では、この脆弱な推移的依存関係を含まない`spring-boot-starter`のバージョンもありません。ただし、推移的依存関係の更新版は利用可能です。`snakeyaml`を2.0に更新すれば問題を解決できます。
繰り返しになりますが、これはあくまで一例です。この記事を読む時点では、更新版の`spring-boot-starter`が公開されている可能性があるため、必ず確認してください。SnakeYamlの脆弱性については、このトピックを詳しく解説した専用のブログ記事をご覧ください。
バージョンプロパティを更新する
まず、更新したいパッケージのバージョンがSpring Bootのプロパティとして定義されているか確認しましょう。Spring Bootのドキュメントには、リリースごとの依存関係のバージョンをまとめた付録があります。そこではバージョンプロパティも確認できます。これらのプロパティはMavenとGradleの両方で上書きでき、推移的依存関係に新しいバージョンを使用できます。
Mavenでは、propertiesセクションにプロパティを追加できます。
Gradleでは、`gradle.properties`ファイルでこのプロパティを編集できます。
`snakeyaml`は単一のライブラリなので、依存関係管理を使うよりこの方法が推奨されます。ただし、複数のライブラリが関係するケースも少なくありません。その場合、バージョンがBOM(部品表)を指すことがあります。これはSBOMとは異なり、同じバージョンで一緒に使う必要があるパッケージ群を表します。たとえば、APIと実装パッケージは、期待どおりに動作するために同じバージョンである必要があります。
依存関係管理の宣言
別の方法として、ビルドツールの機能を使って推移的依存関係を更新できます。この方法は、前のセクションで説明したようにバージョンプロパティを更新できない場合にのみ使用してください。
Mavenでは通常、`dependencyManagement`ブロックに追加します。このブロックを使うと、ライブラリが推移的依存関係として呼び出されるたびに、`dependencyManagement`ブロックで指定した更新版が使用されます。
Maven:
GradleファイルではSpringのdependency-managementプラグインを使っているため、Gradleでもほぼ同様の機能を利用できます。このプラグインは、プロジェクトのひな型を作成したときにSpring Boot initializerによって追加されたものです。
Gradle:
`io.spring.dependency-management`プラグインを使わない場合は、以下のようにGradleの推移的依存関係に制約を追加して更新することもできます。ただし、これらの制約はSpringの`dependency-management`プラグインとうまく併用できません。どちらか一方を選んでください。
SnykでSpring Bootアプリケーションをスキャンする
ソフトウェアのセキュリティと安定性を確保するには、SnykでSpring Bootアプリケーションをスキャンすることが欠かせません。Snykはアプリケーションの依存関係に潜む脆弱性を特定します。放置すれば、悪意のある攻撃者に悪用されるおそれがあります。この記事を読めば、Snykが提示する修正方法をどのように実践するのが最善かもわかります。
定期的にコードベースをスキャンすることで、セキュリティ上の問題に先手を打って対処し、データ侵害などのセキュリティインシデントのリスクを減らせます。スキャンを日常の開発フローに組み込み、脆弱性が見つかった際の対処方法を把握しておきましょう。
以下では、修正前と修正後の両方でSnyk CLIを使ってアプリケーションをスキャンしました。今回は、Spring Boot全体のバージョンを更新し、`snakeyaml`のバージョンプロパティを更新して修正しました。
修正前:

修正後:

SnykでSpring Bootアプリケーションの依存関係に関連する脆弱性が見つかった場合は、次の手順に従ってください。
特定のstarterではなく、Spring Boot全体のバージョンを更新する。
Spring Bootのバージョンを更新する際、Spring Bootの依存関係のバージョンプロパティだけを更新しても不十分です。
MavenまたはGradleの依存関係管理を使って、特定の推移的依存関係を更新する。
CTFを始めよう
オンデマンドのバーチャル入門ワークショップを視聴して、CTFの課題の解き方を学びましょう。



