モジュール java.base
パッケージ java.io

インタフェースObjectInputFilter

関数型インタフェース:
これは関数型インタフェースなので、ラムダ式またはメソッド参照の代入先として使用できます。

@FunctionalInterface public interface ObjectInputFilter
直列化復元中にクラス、配列の長さおよびグラフ・メトリックをフィルタします。

警告: 信頼できないデータの直列化復元は、本質的に危険であり、回避する必要があります。 「Java SEに対するセキュア・コーディングのガイドライン」の"直列化および直列化復元"セクションに従って、信頼できないデータを慎重に検証する必要があります。 「直列化フィルタリング」では、シリアル・フィルタの使いやすさに関するベスト・プラクティスについて説明します。

アプリケーション開発者は、直列化復元の脆弱性から保護するために、各コンポーネントまたはライブラリで直列化復元できるオブジェクトを明確に記述する必要があります。 コンテキストおよびユースケースごとに、開発者は適切なフィルタを作成して適用する必要があります。

直列化復元フィルタリング・ファクトリおよびフィルタ

直列化復元フィルタリングの部分は、フィルタ、コンポジット・フィルタおよびフィルタ・ファクトリです。 各フィルタでは、クラスとリソース制限のチェックが実行され、ステータスが否認済、許可済または未決定として決定されます。 フィルタは、他のフィルタから構成でき、結果をマージまたは結合できます。 フィルタ・ファクトリは、各ObjectInputStreamのフィルタの確立および更新を担当します。

単純なケースの場合、フィルタ・ファクトリを設定せずに、アプリケーション全体に対して静的なJVM全体のフィルタを設定できます。 JVM全体のフィルタは、コマンドラインでシステム・プロパティを使用するか、Config.setSerialFilterを呼び出して設定できます。 カスタム・フィルタ・ファクトリを指定する必要はありません。組込みフィルタ・ファクトリにデフォルト設定されます。 組込みフィルタ・ファクトリは、ObjectInputStreamごとに「静的JVM全体のフィルタ」を提供します。

たとえば、サンプル・クラスを許可し、java.baseモジュールのクラスを許可し、他のすべてのクラスを拒否するフィルタを設定できます : コマンドライン・プロパティとして:

    % java -Djdk.serialFilter="example.*;java.base/*;!*" ...
またはプログラム的に:
    var filter = ObjectInputFilter.Config.createFilter("example.*;java.base/*;!*")
    ObjectInputFilter.Config.setSerialFilter(filter);

複数の実行コンテキストを持つアプリケーションでは、アプリケーションごとにカスタム・フィルタを提供することで、個々のコンテキストを保護するための「フィルタ・ファクトリ」を提供できます。 ストリームが作成されると、フィルタ・ファクトリがコールされ、現在のスレッド・ローカル状態、コール元の階層、ライブラリ、モジュールおよびクラス・ローダーなど、使用可能な情報から実行コンテキストが識別されます。 その時点で、フィルタを作成または選択するためのフィルタ・ファクトリ・ポリシーは、コンテキストに基づいて特定のフィルタまたはフィルタの構成を選択できます。 JVM全体の直列化復元フィルタ・ファクトリにより、コンテキスト固有の直列化復元フィルタをすべてのObjectInputStreamに設定でき、ストリームから読み取られるすべてのオブジェクトをチェックできます。

フィルタ・ファクトリの起動

JVM全体のフィルタ・ファクトリは、各ObjectInputStream「構成され」「ストリーム固有のフィルタが設定された」の場合に呼び出される関数です。 パラメータは現在のフィルタとリクエストされたフィルタで、ストリームに使用されるフィルタを返します。 「ObjectInputStreamコンストラクタ」から起動すると、最初のパラメータはnullで、2番目のパラメータは「静的JVM全体のフィルタ」です。 ObjectInputStream.setObjectInputFilterから呼び出されると、最初のパラメータはストリーム (コンストラクタで設定されたもの)で現在設定されているフィルタで、2番目のパラメータはObjectInputStream.setObjectInputFilterに指定されたフィルタです。 現在および新しいフィルタはそれぞれnullで、ファクトリはnullを返します。 フィルタ・ファクトリの実装では、アプリケーション・スレッド・コンテキストまたはそのコール・スタックから抽出されたコンテキスト情報を自由に使用して、新しいフィルタを作成して組み合せることもできます。 2つのパラメータのみを使用するわけではありません。

アクティブな直列化復元フィルタ・ファクトリは、次のいずれかです:

フィルタ

フィルタは、「パターン文字列」から、または「クラスの述語」からallowまたはrejectクラスに基づいて作成できます。

フィルタcheckInput(FilterInfo)メソッドは、「オブジェクトの読取り」中にゼロ回以上呼び出されます。 メソッドは、クラス、各配列の長さ、ストリームから読み取られるオブジェクト数、グラフの深さおよびストリームから読み取られたバイトの合計数を検証するためにコールされます。

複合フィルタは、他のフィルタの結果を結合またはチェックします。 merge(filter, anotherFilter)フィルタは、2つのフィルタのステータス値を組み合せます。 rejectUndecidedClass(filter)は、ステータスがUNDECIDEDの場合に、クラスのフィルタの結果をチェックします。 多くの場合、フィルタによるALLOWEDではないクラスはREJECTEDにする必要があります。

直列化復元フィルタにより、引数を許可するか拒否するかを決定し、適切なステータスを返します: ALLOWEDまたはREJECTED フィルタがステータスを判別できない場合は、UNDECIDEDを返します。 フィルタは、特定のユース・ケースおよび予想されるタイプ用に設計する必要があります。 特定の用途向けに設計されたフィルタは、フィルタの範囲外のクラスに渡される場合があります。 フィルタの目的がクラスを拒否することである場合は、他の候補クラスでUNDECIDEDを照合し、レポートする候補クラスを拒否できます。 フィルタは、クラスがnullarrayLengthが -1、深さ、参照数およびストリーム・サイズと等しい状態でコールされ、1つまたは一部の値のみを反映するステータスを返します。 これにより、フィルタをレポートしている選択肢に特定でき、許可または否認済ステータスを強制せずに他のフィルタを使用できます。

フィルタ・モデルの例

単純なアプリケーションの場合、許可または拒否されたクラスをリストする単一の事前定義済フィルタで、予期しないクラスの直列化復元のリスクを管理できる可能性があります。

複数のモジュールまたはライブラリから構成されるアプリケーションでは、アプリケーションの構造を使用して、アプリケーションの各コンテキストで許可または拒否するクラスを各ObjectInputStreamで識別できます。 各ストリームの構成時に直列化復元フィルタ・ファクトリが起動され、スレッドまたはプログラムを確認して適用するコンテキスト固有のフィルタを決定できます。 考えられる例:

  • スレッド・ローカル状態は、ストリーム固有のフィルタで適用または構成するフィルタを保持できます。 フィルタは、アプリケーションまたはライブラリによって管理される仮想フィルタのスタックからプッシュおよびポップアップできます。
  • フィルタ・ファクトリは、直列化復元メソッドの呼出し元を識別し、モジュールまたはライブラリ・コンテキストを使用してフィルタを選択するか、適切なコンテキスト固有のフィルタを構成できます。 メカニズムは、直列化されたクラスに対する制限付きアクセスまたは無制限のアクセスを持つ呼び出し元を識別し、それに応じてフィルタを選択できます。

スレッドのすべての直列化復元をフィルタする例

このクラスは、アプリケーション提供のフィルタ・ファクトリがフィルタを組み合せて、スレッドで実行されるすべての直列化復元操作をチェックする方法を示します。 スレッド固有のフィルタを保持するスレッド・ローカル変数を定義し、静的JVM全体のフィルタおよびストリーム固有のフィルタでフィルタを構成するフィルタ・ファクトリを構成し、これら2つのフィルタで処理されないクラスを拒否します。 ストリーム固有のフィルタが設定され、クラスを受け入れたり拒否したりしない場合、JVM全体のフィルタとスレッド・フィルタを組み合わせて適用されます。 doWithSerialFilterメソッドは、スレッド固有のフィルタの設定を行い、アプリケーションRunnableを起動します。
public static final class FilterInThread implements BinaryOperator<ObjectInputFilter> {

    private final ThreadLocal<ObjectInputFilter> filterThreadLocal = new ThreadLocal<>();

    // Construct a FilterInThread deserialization filter factory.
    public FilterInThread() {}

    // Returns a composite filter of the static JVM-wide filter, a thread-specific filter,
    // and the stream-specific filter.
    public ObjectInputFilter apply(ObjectInputFilter curr, ObjectInputFilter next) {
        if (curr == null) {
            // Called from the OIS constructor or perhaps OIS.setObjectInputFilter with no current filter
            var filter = filterThreadLocal.get();
            if (filter != null) {
                // Merge to invoke the thread local filter and then the JVM-wide filter (if any)
                filter = ObjectInputFilter.merge(filter, next);
                return ObjectInputFilter.rejectUndecidedClass(filter);
            }
            return (next == null) ? null : ObjectInputFilter.rejectUndecidedClass(next);
        } else {
            // Called from OIS.setObjectInputFilter with a current filter and a stream-specific filter.
            // The curr filter already incorporates the thread filter and static JVM-wide filter
            // and rejection of undecided classes
            // If there is a stream-specific filter merge to invoke it and then the current filter.
            if (next != null) {
                return ObjectInputFilter.merge(next, curr);
            }
            return curr;
        }
    }

    // Applies the filter to the thread and invokes the runnable.
    public void doWithSerialFilter(ObjectInputFilter filter, Runnable runnable) {
        var prevFilter = filterThreadLocal.get();
        try {
            filterThreadLocal.set(filter);
            runnable.run();
        } finally {
            filterThreadLocal.set(prevFilter);
        }
    }
}

フィルタ・ファクトリの使用

FilterInThreadユーティリティを使用するには、インスタンスを作成し、JVM全体のフィルタ・ファクトリとして構成します。 doWithSerialFilterメソッドは、サンプル・アプリケーションとコア・クラスを許可するフィルタで呼び出されます:
       // Create a FilterInThread filter factory and set
       var filterInThread = new FilterInThread();
       ObjectInputFilter.Config.setSerialFilterFactory(filterInThread);

       // Create a filter to allow example.* classes and reject all others
       var filter = ObjectInputFilter.Config.createFilter("example.*;java.base/*;!*");
       filterInThread.doWithSerialFilter(filter, () -> {
             byte[] bytes = ...;
             var o = deserializeObject(bytes);
       });

特に記載がないかぎり、このインタフェースおよびそのネストされたクラスのメソッドにnull引数を渡すと、NullPointerExceptionがスローされます。

導入されたバージョン:
9
関連項目: