flawopen.com/Javaデシリアライズ/ObjectInputStreamの安全性
ObjectInputStreamは信頼できないデータにも安全ですか?
Javaセキュリティリファレンス
かんたんに説明
通常は安全ではありません。readObject()はJavaオブジェクトを復元し、クラス定義のメソッドを実行する場合があります。添付物に独自の初期化手順まで実行させるフォームのようなものです。悪意あるストリームは既存クラスの挙動に届く可能性があります。コード実行の有無はクラス、ライブラリ、経路、入力境界によります。
危険:ネイティブなオブジェクト復元
// 攻撃者が制御するバイト列をここに渡さない。
try (var in = new ObjectInputStream(untrustedStream)) {
Object value = in.readObject();
handle(value);
}
より安全:固定データ型を解析
// 信頼できない入力では広範な多態型指定を無効にする。
ObjectMapper mapper = new ObjectMapper();
OrderRequest value = mapper.readValue(
untrustedBytes, OrderRequest.class
);
validate(value);
欠陥が到達可能になる経路
API、キュー、キャッシュ、ファイル取込がユーザー制御のバイト列を受け取ります。ObjectInputStream.readObject()に届くと、JVMはプロセス内のシリアライズ可能クラスからオブジェクトを復元します。ガジェットチェーンはその挙動をたどる一つの経路で、全ストリームに特別なペイロードがあるわけではありません。OracleはCVE-2015-4852で、対象WebLogic版へのT3経由の未認証攻撃を記録しました。すべての利用がリモート到達可能という意味ではありません。
ネイティブシリアライズを除去できない場合
- ✓JSONやProtocol Buffersなど明示スキーマの形式を使い、固定DTOへ変換して項目と認可を検証する。
- ✓不可避なら
readObject()の前に用途別ObjectInputFilterを設定し、必要な正確なクラスだけを許可する。 - ✓正常入力を測定し、深さ、参照数、配列、ストリーム長に上限を設ける。許可リストだけでは資源枯渇を防げない。
- ✓信頼できないJSONでは広範な多態型指定を有効にしない。任意のサブタイプ情報でオブジェクトが再生成され得る。
- ✓Javaと依存関係を更新し、不要なライブラリを除去し、旧形式は最小権限と資源制限のもとで処理する。
よくある質問
ObjectInputFilterでreadObject()は安全になりますか?
狭い許可リストと読込前の制限でリスクは下がりますが、万能なサニタイザーではありません。許可クラスと動作、フィルターの有効化、アプリ側検証と認可が重要です。可能ならユーザー制御データにネイティブ形式を使わないでください。