SnakeYaml 2.0:安全でないデシリアライゼーションの脆弱性を解決する
2023年6月21日
0 分で読めます昨年12月、CVE-2022-1471についてお知らせしました。この安全でないデシリアライゼーションの問題は、条件がそろうと容易に任意コード実行につながる可能性があります。
詳しく解説したブログ記事「SnakeYamlの安全でないデシリアライゼーションの脆弱性(CVE-2022-1471)」では、このライブラリの問題と、その悪用方法について説明しました。問題の要点は、SnakeYamlがデフォルトで入力されたyamlを汎用オブジェクト型として解析することでした。そのため、クラスパス上にある別のクラスをデシリアライズできてしまいます。ClassCastExceptionがスローされたとしても、オブジェクトがすでにロードされていれば、被害は発生しています。
影響の大きさは、ライブラリの使い方に大きく左右されます。たとえば、多くの開発者はアプリの設定にyamlを使用するだけです。この脆弱性が悪用されるのは、エンドユーザーなど、信頼できないソースからyamlを受け入れる場合に限られます。それでも、このようなライブラリがどのように使われるかを予測することはできないため、デフォルト設定は安全であるべきです。
Snyk Open SourceでSnakeYamlをアップグレードする
Snyk Open Sourceを使って、古いSnakeYamlライブラリの代替を探してみましょう。Snyk CLIでローカルからsnyk testを実行すると、代替バージョンがあることがわかります。

Webインターフェースでも、問題を解決するSnykYaml 2.0のバージョンが利用可能であることが示されます。唯一の問題は、Spring Boot 3にはまだ1.xバージョンが含まれていることです。そのため、MavenまたはGradleのマニフェストファイルで、バージョンを手動で置き換える必要があります。

ライブラリを新しいメジャーバージョンに手動で変更すると、問題が起きる可能性があることに注意してください。変更を安易に行わず、アプリケーションの内部動作に及ぼす影響を理解しておきましょう。
SnakeYaml 2.0でデシリアライゼーションの脆弱性を緩和する
任意コード実行につながる可能性のあるデフォルトの動作を緩和するため、SnakeYaml 2.0は2023年初頭にリリースされました。このバージョンでは、新しいyaml()で使用されるコンストラクタがSafeConstructorを継承するようになりました。そのため、解析できる型は限定されています。SnakeYamlのSafeConstructorでは、プリミティブ型や文字列、マップなど、標準的なJavaクラスを構築できます。
特定の型は、デフォルトでは解析できなくなりました。そのため、以下のyamlファイルを読み込むと例外が発生します。
これで、デフォルトの実装は脆弱ではなくなりました。ただし、これは互換性を破る変更のため、これまでのコードは動作しなくなる可能性があります。
SnakeYaml 2.xを使う際にYamlの解析ロジックを修正する方法
まず、SnakeYaml 1.xを使わないようにする必要があります。最新のSpring Boot 3.1でさえ、現時点ではSnakeYaml 2.xを同梱していません。そのため、マニフェストファイルで自分でアップグレードする必要があります。Mavenの場合、pomファイルの<dependencyManagement>セクションを利用できます。ほかにも方法はあります。Gradleでは、依存関係の制約を使って推移的依存関係を更新することもできます。
SnakeYaml 2.xでは、以前のバージョンからAPIに互換性のない変更があります。そのため、再び動作させるには、新しい安全なデフォルト設定に合わせてyamlの解析処理を書き換える必要があります。
2つのクラスからなる、ごくシンプルなドメインを考えてみましょう。
Person
Comment
Person.java:
Comment.java:
上記のようなエンティティからyamlファイルを作成する場合、SnakeYaml 1.xでは次のようなコードを書いていたことでしょう。
その結果、次のyamlファイルが生成されます。
SnakeYaml 2.xでは、!!mypackage.Personは受け付けられなくなりました。オブジェクトをyamlファイルに変換する際に、オブジェクトへの参照を取り除けるようになりました。しかし、移行前にエクスポートしたyamlファイルには、まだ問題が残っています。
幸い、この問題も解決できます。特定のオブジェクトに解析する場合は、パーサーが使用するコンストラクタを設定できます。さらに、LoaderOptionsに特定のTagInspectorを追加すると、パッケージタグを許可できます。これにより、オブジェクトに適合するyamlファイルだけを許可し、以前の1.xバージョンで作成されたyamlとの後方互換性を確保できます。
さらに、yamlファイルから実際のオブジェクトへの参照、つまりタグを完全に取り除くのが望ましいでしょう。これは以前のSnakeYamlでも可能でした。yamlオブジェクトにrepresenterを追加し、トップレベルオブジェクトのタグをmapに対応付けます。以下は、SnakeYaml 2.xと互換性のある例です。
yamlファイルの先頭に!!mypackage.Person(または同様のタグ)が付かなくなります。すべてのyamlファイルからタグが取り除かれていれば、パーサーからTagInspectorを削除できます。
Snykの最新情報をチェック
オープンソースのセキュリティを確保するには、ライブラリを常に最新バージョンに保つことが重要です。SnakeYaml 1.xを使っていると、外部ソースのyamlファイルを直接または間接的に受け入れた場合に、不要なセキュリティ上の問題につながる可能性があります。
Snyk Open Sourceを使えば、こうした問題を見つけて修正したり、必要に応じて代替バージョンを確認したりできます。次の例では、SnakeYamlをバージョン2.0以上に更新することで、任意コード実行の脆弱性を解消できることを示しています。

GitリポジトリをSnykに接続すると、重大なセキュリティ問題がない場合でも、依存関係を最新の状態に保つためのプルリクエストを作成できます。問題を未然に防ぐことが最善です。ライブラリを最新の状態に保つことで、脆弱性のリスクを最小限に抑え、セキュリティ問題への対応に伴う余分な作業も減らせます。

CTFを始めよう
オンデマンドのバーチャル入門ワークショップを視聴して、CTFの課題の解き方を学びましょう。


