デシリアライズの脆弱性への対処

信頼できないデータを受け入れ、デシリアライズするアプリケーションは、攻撃に対して脆弱です。デシリアライズされる前に、シリアライズ・オブジェクトの着信ストリームに対するフィルタを作成できます。

デシリアライズの本質的な危険性

信頼できないデータ(特に不明、信頼できない、または認証されていないクライアントからのデータ)のデシリアライズは、本質的に危険なアクティビティです。これは、受信データ・ストリームのコンテンツによって、作成されるオブジェクト、フィールドの値、およびそれらの間の参照が決定されるためです。ストリームを慎重に構築することで、攻撃者は悪意を持って任意のクラスのコードを実行できます。

たとえば、オブジェクトの構築に、状態を変更したり他のアクションを呼び出したりする副次的な影響がある場合、これらのアクションによって、アプリケーション・オブジェクト、ライブラリ・オブジェクト、さらにはJavaランタイムの整合性が損なわれる可能性があります。ガジェット・クラスは、クラスの作成やメソッドの呼出しなどの任意の反映型アクションを実行できますが、悪意を持ってデシリアライズされて、サービス拒否やリモート・コード実行を引き起こす可能性があります。

デシリアライズ攻撃を無効にするためのキーは、任意のクラスのインスタンスがデシリアライズされないようにし、そのメソッドの直接または間接的な実行を防ぐことです。これは、シリアライズ・フィルタを介して行うことができます。

Javaのシリアライズおよびデシリアライズの概要

オブジェクトは、その状態がバイト・ストリームに変換されると、シリアライズされます。ストリームはファイル、データベースにまたはネットワーク上に送信されます。Javaオブジェクトは、そのクラスまたはそのスーパークラスのいずれかがjava.io.Serializableインタフェースまたはjava.io.Externalizableサブインタフェースのいずれかを実装している場合にシリアライズ可能になります。JDKでは、シリアライズは、Remote Method Invocation (RMI)、プロセス間通信(IPC)プロトコル(Spring HTTPインボーカなど)のカスタムRMI、Java Management Extensions (JMX)などの多くの領域で使用されます。

オブジェクトは、そのシリアライズされた形式がオブジェクトのコピーに変換されると、デシリアライズされます。この変換のセキュリティを確保することが重要です。デシリアライズではコードが実行されます。これは、デシリアライズされるクラスのreadObjectメソッドにカスタム・コードが含まれている可能性があるためです。

シリアライズ・フィルタ

シリアライズ・フィルタを使用すると、アプリケーションで許容されるクラスおよび拒否されるクラスを指定できます。フィルタを使用すると、オブジェクト・グラフが妥当な限度を超えないように、デシリアライズ中にオブジェクト・グラフのサイズと複雑度を制御することもできます。フィルタは、プロパティとして構成することも、プログラム的に実装することもできます。

ノート:

シリアライズ・フィルタは、デフォルトでは有効化も構成もされていません。システム・プロパティまたはセキュリティ・プロパティでフィルタを指定するか、ObjectInputFilterクラスで設定しないかぎり、シリアライズ・フィルタリングは行われません。
デシリアライズの脆弱性の回避に役立てるために、フィルタを作成する以外に、次のアクションを実行できます。
  • 信頼できないデータをデシリアライズしません。
  • SSLを使用してアプリケーションの間の接続を暗号化および認証します。
  • readObjectメソッドを使用してオブジェクトの不変をチェックするなど、割当ての前にフィールドの値を検証します。

ノート:

ビルトイン・フィルタは、RMIに用意されています。ただし、これらのビルトイン・フィルタは、開始点としてのみ使用してください。拒否リストの構成または許可リストの拡張、あるいはその両方を行って、RMIを使用するアプリケーションの保護を追加します。「ビルトイン・フィルタ」を参照してください。

これらおよびその他の方針の詳細は、Java SEのセキュアなコーディングのガイドラインシリアライズとデシリアライズを参照してください。