---
title: "安全でないデシリアライゼーションとは？RCEに至る仕組みと言語別の防御実装を解説"
url: "https://www.issoh.co.jp/tech/details/16369/"
published: 2026-08-10
updated: 2026-11-04
categories: ["脆弱性・インシデント"]
publisher: "株式会社一創"
---

# 安全でないデシリアライゼーションとは？RCEに至る仕組みと言語別の防御実装を解説

受け取ったバイト列をそのままオブジェクトへ戻す処理が、任意コード実行の入口になります。安全でないデシリアライゼーション（Insecure Deserialization）はCWE-502として整理された欠陥で、Javaの`ObjectInputStream`、PHPの`unserialize`、Pythonの`pickle`が代表的な発生源です。本記事では、ガジェットチェーンでRCEに到達する流れ、言語ごとに用意された防御機構と適用できるバージョン、JSONやYAMLへ移しても残る経路、稼働中のシステムを止めずに直す段階手順までを実装目線で整理します。読み終えた時点で、自社コードのどこから潰すかが決まります。

## まとめ：安全でないデシリアライゼーション対策の結論と優先順位

結論を先に置きます。この欠陥を止める本命は、信頼できない入力をオブジェクト復元APIへ渡さない設計に変えることです。`ObjectInputStream`や`unserialize`、`pickle`が読み込むのは「データ」ではなく「オブジェクトを再構築する手順」でした。復元の途中でコンストラクタや特殊メソッドが動くため、復元後に値を検査しても遅い。入力を文字列として検査する発想では防げません。

置換が終わるまでの緩和策は許可リスト方式のフィルタです。JavaはJDK 9のJEP 290で入った`ObjectInputFilter`、JDK 17のJEP 415で追加されたフィルタファクトリ。PHPは`unserialize`の`allowed_classes`、Pythonは`Unpickler.find_class`のオーバーライド。いずれも復元してよいクラスを列挙する方式で、拒否リストの更新に頼りません。

逆に、単独では対策にならない手が3つあります。署名の付与だけで済ませること、WAFのシグネチャに任せること、既知ガジェットを含むライブラリを1本外して終わりにすること。着手順は、危険APIの呼び出し箇所を棚卸しし、信頼境界をまたぐ入口からJSONなどのデータ専用フォーマットへ置換し、置換できない箇所にフィルタを当てる、の3段です。

## 安全でないデシリアライゼーションの定義とRCEへ至る攻撃連鎖の全体像

まず言葉の範囲を揃えます。攻撃が成立する条件と、成立したときに何が起きるかを分けて把握すると、後段の対策選定が速くなります。

### シリアライズとデシリアライズの役割分担とCWE-502が指す欠陥

シリアライズは、メモリ上のオブジェクトをファイルやネットワークで運べるバイト列・文字列へ変換する処理です。デシリアライズはその逆で、受け取った表現からオブジェクトを組み立て直します。問題は、多くの言語の標準形式が「値」だけでなく「クラス名」を持ち、復元側がその名前を見てクラスをロードする点にあります。

CWE-502はこの欠陥を「信頼できないデータのデシリアライゼーション」と定義しています。OWASP Top 10では2017年版でA08として独立項目でしたが、2021年版でソフトウェアとデータの整合性不備へ統合され、2025年版でもA08「整合性不備」の枠内に収まりました。項目名が消えたことと、脅威が消えたことは別です。カテゴリの再編経緯は[OWASP Top 10 2025年版の10項目と2021年版からの変更点](https://www.issoh.co.jp/tech/details/9917/)で整理しています。

### マジックメソッドとガジェットチェーンでRCEに到達するまでの流れ

攻撃は3段構えです。第1段は、復元時に自動で呼ばれるメソッド。PHPの`__wakeup`と`__destruct`、Javaの`readObject`、Pythonの`__reduce__`がこれにあたります。第2段は、その先で呼ばれる危険な処理（sink）で、リフレクション経由のメソッド呼び出しやプロセス起動が該当します。第3段が、両者をつなぐ既存クラスの連鎖です。

この連鎖をガジェットチェーンと呼びます。攻撃者は新しいコードを送り込むのではなく、アプリのクラスパスに元からあるクラスを部品として並べ替えるだけ。Java向けにはysoserialというペイロード生成ツールが公開されており、Apache Commons Collectionsを使った連鎖はOracle WebLogicのCVE-2015-4852など実被害を出しました。RCEが成立する5つの経路の全体像と、侵入後の検知・封じ込めの手順は[RCE（リモートコード実行）とは](https://www.issoh.co.jp/tech/details/19286/)で扱っています。攻撃コードそのものの分類は[exploitの仕組みと種類](https://www.issoh.co.jp/tech/details/15280/)で解説しています。

### 権限昇格・DoS・状態改ざんを含む被害範囲と深刻度の切り分け

被害はRCEだけではありません。使えるガジェットが見つからない環境でも、シリアライズされたセッションオブジェクトの`isAdmin`相当のフィールドを書き換えれば権限昇格が成立します。深くネストした構造を送り込めばスタックを消費させるサービス停止も起こせる。PHPが7.4で`max_depth`（既定4096）を追加したのは、この種の入力への対処でした。

深刻度の切り分けは実務的に2軸で足ります。復元されたオブジェクトが認可判断に使われるか、そしてクラスパスに既知のガジェットを含むライブラリがあるか。前者が真なら、RCEに至らなくても権限昇格として扱う。両方が真なら、緩和策を挟む前に該当エンドポイントを止める判断が要ります。復元処理を経ずに認可判定そのものが抜けている場合の切り分けは[認可バイパスの仕組みとサーバ側で止める実装対策](https://www.issoh.co.jp/tech/details/16399/)で整理しました。

## 言語別の危険なAPIと現行ランタイムが備える防御機構の対応表

言語ごとに、危険なAPIと標準で用意された歯止めは大きく違います。手元のスタックがどの段階にあるかを先に確定させてください。

### Javaのシリアライゼーションフィルタと版ごとの適用範囲の違い

JavaはJDK 9で入ったJEP 290により、`ObjectInputFilter`でクラス名・配列長・深さ・参照数に上限を課せます。JVM全体へ効かせる`jdk.serialFilter`と、ストリーム単位で設定する方式の2通り。ただしJVM全体に1本のフィルタを置く運用は、ライブラリが何層も重なるアプリだと広すぎるか狭すぎるかのどちらかに倒れます。

JDK 17のJEP 415が追加したのがフィルタファクトリです。`ObjectInputStream`が生成されるたびに呼ばれる工場を1つ登録し、呼び出し文脈ごとに別のフィルタを返す。既存の復元箇所へ手を入れずに、文脈別のポリシーを合成できます。判断としては、JDK 17以降ならフィルタファクトリ、JDK 11に留まる資産はストリーム単位のフィルタで個別に塞ぐ、という切り分けが現実的です。

### PHPのunserializeとallowed\_classes指定の限界

PHPの`unserialize`は第2引数のオプション配列で`allowed_classes`を取ります。PHP 7.0で追加された指定で、`false`ならすべてのオブジェクトが`__PHP_Incomplete_Class`になり、クラス名の配列を渡せばその範囲だけ復元されます。既定値は`true`、つまり無制限です。

ここで注意したいのが公式マニュアルの警告文です。`allowed_classes`の値にかかわらず、信頼できないユーザー入力を`unserialize`へ渡してはならない、と明記されています。オブジェクトの生成とオートロードを通じてコードが読み込まれ実行される余地が残るためです。つまり`allowed_classes`は移行期間の緩和策であって、恒久対策ではありません。恒久対策は`json_decode`への置換です。

### Python・Ruby・.NETで危険なAPIと代替手段の対応表

主要ランタイムの現状を1枚に並べます。既定の防御機構が「なし」の欄は、言語側が守ってくれないという意味で、実装側で入口を塞ぐ以外に手がありません。

| 言語・ランタイム       | 危険なAPI            | 既定の防御機構            | 実務での代替           |
| -------------- | ----------------- | ------------------ | ---------------- |
| Java（JDK 17以降） | ObjectInputStream | フィルタファクトリ          | JSON＋許可リスト       |
| PHP 8系         | unserialize       | allowed\_classes指定 | json\_decode     |
| Python 3系      | pickle.loads      | なし（公式が警告）          | json＋HMAC署名      |
| Ruby 3系        | Marshal.load      | なし                 | JSONへ置換          |
| .NET 9以降       | BinaryFormatter   | 実装を削除済み            | System.Text.Json |

Pythonの公式ドキュメントは「pickleは安全ではない。信頼するデータだけをunpickleせよ」と明言し、改ざん検知が要るなら`hmac`での署名を検討するよう書いています。制限付きで使う場合は`Unpickler.find_class`をオーバーライドし、許可するモジュールとクラス名だけを返す実装例も掲載されています。

## JSON・YAML利用時にも残るデシリアライゼーション経路の落とし穴

フォーマットをJSONやYAMLへ変えても、ライブラリ設定次第でクラス名から任意の型を組み立てる経路が復活します。移行後に見落とされやすい2つの型を押さえます。

### Jacksonのポリモーフィック型指定で生じる任意クラス復元

Javaで広く使われるjackson-databindには、JSONの中に型名を埋めて多態を復元する機能があります。古い`enableDefaultTyping()`を有効にすると、入力側が指定した型名でクラスをロードするため、JDBCデータソース系のクラスを踏み台にした攻撃が成立しました。CVE-2017-7525を皮切りに、同型の報告が長く続いています。

2.10で導入された`activateDefaultTyping(PolymorphicTypeValidator, ...)`が現在の正解です。`enableDefaultTyping()`は非推奨となり、許可する型を開発者が明示する形へ変わりました。拒否リストを更新し続ける運用から、許可リストを宣言する運用への転換です。依存ライブラリの版と既知脆弱性の突き合わせ自体は[SCA（ソフトウェア構成分析）の仕組みとSAST・SBOMとの違い](https://www.issoh.co.jp/tech/details/16216/)で扱っています。

### SnakeYAMLのSafeConstructor既定化と旧版に残るリスク

YAMLも同じ構図でした。SnakeYAMLは1.x系の既定で汎用オブジェクトへの復元を許し、クラスパス上の任意クラスを組み立てられたためCVE-2022-1471として報告されています。設定ファイルの読み込みに使っていたライブラリが、そのまま入力経路になっていた形です。

2.0では`Constructor`が`SafeConstructor`を継承する形に変わり、既定でプリミティブと基本コレクションだけを扱います。1.x系に留まる場合は、`SafeConstructor`を明示的に渡す実装へ直すのが緩和策。判断は単純で、外部から来るYAMLを読む箇所が1つでもあるなら、版上げを他の改修より前に置いてください。

## 既存システムでの段階的な移行手順と移行できない場合の緩和策の設計

稼働中のシステムでは、危険APIを一斉に消す改修は現実的ではありません。入口の性質で優先度をつけ、順に信頼境界の外側から塞ぎます。

### 入口の棚卸しからフォーマット置換までの4段階の移行手順と検証

手順は4段階に分けると管理できます。各段階の完了条件を先に決めておくと、途中で止まっても現在地が分かります。

1. 危険APIの呼び出し箇所を全文検索で列挙し、ファイルと行番号の一覧を作る（Javaはストリーム生成箇所、PHPは復元関数、Pythonはロード関数）
2. 各箇所の入力元を、外部リクエスト・内部キュー・自プロセス生成の3種に分類し、外部リクエスト由来を最優先に置く
3. 外部由来の箇所からJSONなどデータ専用フォーマットへ置換し、送信側と受信側を同一リリースで切り替える
4. 置換後、旧形式のペイロードを送って復元が拒否されることを回帰テストで確認し、拒否ログが出ることまで見る

4段目を省くと、旧形式を受け付けるフォールバックが残ったままリリースされる事故が起きます。移行の完了条件は「新形式が動くこと」ではなく「旧形式が拒否されること」です。

### 置換できない箇所へ適用する許可リスト方式フィルタの設計と基準

外部ライブラリの内部で復元が起きる場合など、置換できない箇所は残ります。ここに当てるフィルタの設計基準は4つ。復元を許すクラスを列挙すること、配列長・オブジェクト参照数・ネスト深さに上限を置くこと、拒否をアプリのログとして残すこと、そして入口ごとに別のポリシーを持たせることです。

上限値は本番のペイロードを実測してから決めます。ネスト深さは実測値の2倍程度、参照数は余裕を持たせて丸めるのが扱いやすい。文字列の中身を検査するルールは書かない方がよく、その理由は復元前に型が確定していないためです。入力の値そのものを検査する対策の適用範囲は[入力バリデーションで防げる攻撃の範囲と許可リスト設計](https://www.issoh.co.jp/tech/details/16364/)で切り分けています。

### HMAC署名を併用する場合の鍵管理と検証順序に関する判断基準

クッキーや隠しフィールドに状態を持たせる設計では、HMAC署名の併用が選ばれます。ここで守る順序は1つだけ。署名を検証してから復元する、です。復元してから署名を見る実装は、検証前にコードが動くため意味を成しません。

鍵はソースへ埋めずシークレット管理サービスから読み、比較は定数時間比較の関数を使います。鍵のローテーションは旧鍵での検証を一定期間だけ許す二重受け入れで実施する。ただし署名で守れるのは改ざんの検知までで、復元処理そのものの安全性は担保されません。署名は許可リストの代わりにはなりません。

## 対策として採用してはいけない設計と実務で繰り返される失敗パターン

ここからは判断を言い切ります。現場で「対策済み」と報告されがちで、実際には塞げていない3つの型です。

### 署名付与のみで対策が完了したと見なす設計を採用しない理由と条件

署名だけを対策とする設計は採用しません。理由は、署名鍵が漏れた瞬間に防御がゼロへ戻ること、そして署名を検証しても復元先クラスが無制限のままである点にあります。鍵の漏えい経路は、設定ファイル・CIのログ・古いリポジトリ履歴です。復元先が無制限なら、鍵を得た攻撃者はそのままRCEへ進めます。

署名のみで許容できる場面は限定的です。自プロセスが生成して自プロセスだけが復元する短命キャッシュで、復元先クラスが固定され、鍵がシークレット管理下にある場合。この3条件が同時に成り立たないなら、署名に加えて許可リストのフィルタを必ず置いてください。

### WAFのシグネチャ頼みとガジェット削除だけで止める判断の限界

WAFのシグネチャに任せる判断も採用できません。シリアライズ済みデータはBase64やgzip、多重エンコードで容易に見た目を変えられ、パターン照合は回避されます。WAFは既知ペイロードの初期観測を減らす層であって、脆弱な復元処理を安全にする層ではない。仮想パッチとして時間を稼ぐ用途に限定してください。

もう1つが、既知ガジェットを含むライブラリを1本外して完了とする判断です。ysoserialが公開しているガジェットチェーンは数十種類あり、依存が入れ替われば別の連鎖が成立します。ライブラリを外す作業は「今日のペイロードを無効化する」だけで、復元処理を許可リストで囲う作業の代わりにはなりません。

### サポート外パッケージでBinaryFormatterを延命する選択の見送り基準

.NETでは廃止の道筋が明示されています。BinaryFormatterは.NET 5でSYSLIB0011として非推奨になり、.NET 8ではほとんどのプロジェクト種別で実行時に例外を投げるようになりました。.NET 9からはランタイム内の実装自体が削除され、APIは残るものの常に例外を返します（.NET Frameworkは対象外）。

その状態でも動かす手段として、サポート外のNuGetパッケージを参照する選択肢が案内されています。この選択は見送りが妥当です。基準は3つ。セキュリティ修正が提供されないこと、次のランタイム更新で再び動かなくなる可能性が残ること、そして移行先の`System.Text.Json`が標準で用意されていること。延命に充てる工数は、シリアライズ対象のDTO化に回した方が回収できます。

## SAST・SCA・DASTによる検出の役割分担と診断の使い分け基準

この欠陥は、単一のツールでは見つけ切れません。何がどこまで見えるかを把握し、残った範囲を人が見る設計にします。

### SAST・SCA・DASTが検知できる範囲と取りこぼしの境界

SASTは危険APIの呼び出し箇所を機械的に列挙できます。棚卸しの初手として有効ですが、その引数が外部由来かどうかの追跡はフレームワーク境界で切れやすく、誤検知と見逃しが同時に出ます。SCAは既知ガジェットを含むライブラリ版の検出に強く、jackson-databindやSnakeYAMLの版判定はこちらが速い。

DASTは苦手です。復元に成功しても応答が変わらないブラインド型が多く、外部通信を観測する仕掛けを併用しないと成立を確認できません。境界を整理すると、呼び出し箇所はSAST、ガジェットの在庫はSCA、実際に到達可能かは手動検証、という分担になります。

### 実行時防御と外部の脆弱性診断を組み合わせる際の判断基準と分岐点

実行時側の防御は、JVMのフィルタのように言語標準の機構を先に使い、それで覆えない範囲へ実行時保護の製品を検討する順序が無駄になりません。逆順で製品を先に入れると、標準機構で塞げたはずの箇所まで製品依存になります。

分岐点は、危険APIの呼び出しが自社コードの外にあるかどうかです。自社コード内なら改修で閉じられます。フレームワークやミドルウェアの内部にあり、版上げでも消えない場合は、到達可能性の確認を外部の手動検証に回すのが早い。判断材料が足りないときは[脆弱性診断・セキュリティ診断](https://www.issoh.co.jp/service/system/vulnerability/)で対象エンドポイントを絞った検証から始められます。

## よくある質問：安全でないデシリアライゼーションの実装判断と運用

実装と運用の現場で判断が割れやすい5点に答えます。

### 安全でないデシリアライゼーションとインジェクションは何が違いますか？

インジェクションは、文字列として渡した入力が命令として解釈される欠陥です。SQLやOSコマンドが典型で、プレースホルダやエスケープという「値と命令を分ける」対策が効きます。デシリアライゼーションは、入力が最初からオブジェクトの構築手順として解釈される点が違います。値と命令を分ける前提が成り立たないため、エスケープでは止まりません。復元してよい型を列挙するか、そもそも復元しない形式へ変えるかの二択になります。

### JSONへ移せばデシリアライゼーションの脆弱性は起きなくなりますか？

起きなくなるとは言えません。JSON自体はクラス名を持たない素直なデータ形式ですが、ライブラリ側で多態復元を有効にすると型名から任意クラスを組み立てる経路が復活します。jackson-databindの`enableDefaultTyping()`がその例です。移行時は、フォーマットを変えるだけでなく、型名を入力から受け取る設定を無効にし、必要なら許可リストを宣言する`activateDefaultTyping`へ書き換えてください。

### Javaのシリアライゼーションフィルタを設定すれば対策として十分ですか？

単独では不十分です。フィルタは強力ですが、JVM全体に1本だけ置く運用では、ライブラリが多層に重なるアプリで範囲が広すぎるか狭すぎるかに倒れます。JDK 17以降はフィルタファクトリで文脈ごとにポリシーを分け、あわせて配列長・深さ・参照数の上限を設定してください。加えて、外部から来る入力の復元をJSONへ置き換える作業は続けます。フィルタは移行を安全に進めるための足場という位置づけです。

### 攻撃を受けたかどうかはアクセスログから判別できますか？

標準的なアクセスログだけでは困難です。ペイロードはPOSTボディやクッキーに入り、Base64などで符号化されているため、URLとステータスコードの記録には現れません。判別には、復元処理の拒否イベントをアプリ側でログに出す実装が要ります。フィルタで拒否したクラス名と入口の識別子を記録しておけば、試行の有無が後から追えます。導入時にこのログ設計を同時に入れてください。

### 既存システムの危険な箇所を洗い出す最短の手順はありますか？

全文検索から始めるのが最短です。Javaはストリーム生成箇所、PHPは復元関数、Pythonはロード関数、.NETは廃止済みフォーマッタを対象に、ファイルと行番号の一覧を作ります。次に依存ライブラリの版を確認し、jackson-databindやSnakeYAMLが古い版で止まっていないかを見る。最後に、列挙した各箇所の入力元を外部・内部・自プロセスの3種に分類すれば、着手順が決まります。

## 関連記事

- [SASTとは？DAST・SCAとの違いとCI/CDへの組み込み・導入判断を実装視点で解説](https://www.issoh.co.jp/tech/details/15880/)：危険APIの呼び出し箇所を機械的に洗い出す工程の設計に使えます。
- [RASP（実行時アプリケーション自己保護）とは？WAFとの違いと導入判断を実装視点で解説](https://www.issoh.co.jp/tech/details/16230/)：言語標準のフィルタで覆えない範囲を実行時に守る選択肢の判断材料です。
- [脅威モデリングとは？STRIDEでの脅威抽出手順とツール選定を実装目線で解説](https://www.issoh.co.jp/tech/details/16226/)：どの入口が信頼境界をまたぐかを設計段階で洗い出す手法です。
- [脆弱性とは？種類・CVE/CVSSの仕組みと発見から修正までの実務を解説](https://www.issoh.co.jp/tech/details/13546/)：CWEやCVSSの読み方と、発見から修正までの流れを整理しています。
- [APIセキュリティとは？OWASP API Top 10の主要リスクと実装対策を解説](https://www.issoh.co.jp/tech/details/13793/)：API境界で受け取るペイロード全般のリスクを俯瞰できます。

---

出典: [安全でないデシリアライゼーションとは？RCEに至る仕組みと言語別の防御実装を解説](<https://www.issoh.co.jp/tech/details/16369/>)（株式会社一創）
