セキュリティ対策
安全でないデシリアライズ — 危ないのは「データ」ではなく「データに型を選ばせること」
受け取ったバイト列を元のオブジェクトに戻す処理は、実装によっては『どのクラスを作るか』まで外部データに決めさせます。OWASPはこの類型がサービス停止・アクセス制御の迂回・リモートコード実行に至ると述べ、.NETのBinaryFormatterについては『危険であり、安全にすることはできない』と明言しています。純粋なデータ形式への切り替えと署名による整合性検証を軸に解説します。
受け取ったバイト列を元のオブジェクトに戻す——この処理が危険になるのは、中身が変なデータだからではありません。形式によっては、「どの型のオブジェクトを組み立てるか」まで外部データが決められるからです。
なぜ「入力検証」では間に合わないのか
純粋なデータ形式(JSON / XML)
外部データが決めるのは値だけ → 受け取ってから、自分の型に詰め替える → 検証が効く
オブジェクトを復元する形式
外部データが決めるのは値と「型」の両方 → 復元の過程で選ばれた型のコードが動く → 値を検証する場所に到達しない
多くの入力検証は「値が正しいか」を見ます。しかしオブジェクトを復元する形式では、復元の過程そのもの——どのクラスを実体化し、その過程でどのコードが動くか——が外部データに左右されます。あなたの検証コードが呼ばれる前に、すでに何かが実行され終えていることがあり得るのです。
これは前に扱った プロトタイプ汚染 と同じ構図です——外部データが、値ではなく「構造」を決めてしまう。名前も言語も違いますが、防ぎ方の発想は共通しています。
何が起きるのか(OWASPが挙げる3つ)
- サービス停止(DoS)
- 復元処理そのものを重くする・壊すことでアプリを止める
- アクセス制御の迂回
- 権限やロールを表すオブジェクトを、外部から都合よく組み立てられる
- リモートコード実行(RCE)
- 復元の過程で呼ばれる処理を連鎖させ、任意のコード実行に至る。最悪クラスの結果
「うちのフレームワークは大丈夫」とは限りません
これは古い言語だけの話ではありません。当サイトがNVDのデータでNext.jsの脆弱性を数えたとき、CWEの上位にデシリアライズ(CWE-502)が入っていました——Server Actions のようにリクエストのボディをデシリアライズする経路を、現代のフレームワークは標準で持っているからです(Next.jsとReactは脆弱性が多いのか)。「自分では書いていない」=「存在しない」ではありません。
対策の軸は2つ
① 型を選ばせない(第一選択)
OWASPの表現はこうです——「JSONやXMLのような純粋なデータ形式に切り替えることで、独自のデシリアライズ処理が悪意ある目的に転用される可能性を減らせる」。
外部から来るものは値だけを運ぶ形式で受け取り、自分のコードで自分の型に詰め替える。この一手で、攻撃者から「何を作るか」を選ぶ権利を取り上げられます。多くの現場で、これだけで問題が消えます。
② 署名して、無いものは復元しない
独自形式をどうしても使う場合、OWASPは「シリアライズの過程で署名し、認証された署名を持たないメッセージはデシリアライズしないという選択ができる」としています。
ポイントは復元する前に検証すること。復元してから中身を確かめるのでは、上で書いた理由により手遅れになり得ます。順序がすべてです。
設定では安全にできない仕組みがある
OWASPは .NET の BinaryFormatter について、「この型は危険であり、安全にすることはできない」と明言しています。
この一文は、実務上とても重要です——世の中には「正しく使えば大丈夫」が成り立たない道具が実在します。オプションを固める、検証を足す、許可リストを書く……そのどれでも安全にならない。唯一の対策は使わないことです。
だから点検では、まず「これは設定で守れるものか、そもそも守れないものか」を分けてください。後者に時間を使うのは、対策ではなく先延ばしです。
言語別に、OWASPが名指ししているもの
- PHP
unserialize()の使用を避け、JSONを優先する- Python
pickle/c_pickle、PyYAML のload、jsonpickleは危険として挙げられている- Java
ObjectInputStream#resolveClass()をオーバーライドして、復元できるクラスを制限する- .NET
BinaryFormatterは危険であり、安全にすることはできない(使用しない)
共通しているのは、言語が用意している「便利な永続化機構」ほど、外部データに向けてはいけないという点です。それらは信頼できる相手との間でオブジェクトを丸ごと運ぶために作られており、敵対的な入力を想定していません。
自分のコードで確認すること
外部データが最初に触れる場所を、全部書き出す
リクエストボディ、クッキー、セッション、キュー、ファイルアップロード、Webhook、キャッシュ——「どこかで保存して、後で戻している」場所をすべて洗い出します。セッションやキャッシュを見落としやすい(自分が書いたデータのつもりでも、経路によっては外部が触れます)。
そのうち「型まで復元する形式」を使っている箇所を特定する
上の言語別リストにある関数・クラスを検索します。ここが最優先で潰す対象です。設定では守れない機構(BinaryFormatter等)を使っている場合、優先度は最上位——移行以外の解決がありません。
純粋なデータ形式へ移す
JSONやXMLで受け取り、自分のコードで自分の型に詰め替える。詰め替えの際にスキーマ検証を掛ければ、想定外のキーも同時に閉じられます(プロトタイプ汚染の対策と同じ手当てです)。
移せないものは署名で縛る
形式を変えられない場合は、シリアライズ時に署名し、復元の前に署名を検証します。署名が無ければ復元しない——これを既定にしてください。鍵の扱いは .envとAPIキーの基礎 のとおり、コードと同じ場所に置かないこと。
依存の中にある復元処理も数える
自分が書いていなくても、依存が復元していることがあります。CWE-502として公開されるCVEは継続的に出ているので、機械監視に載せてください(osv-scannerの導入と使い方 / CVE対応の実務手順)。
当サイトの視点:入力の「値」ではなく「権限」を見る
入力検証というと、多くの人が値の妥当性——長さ、形式、範囲——を思い浮かべます。しかしこの記事の脅威は、そこに到達する前に成立します。当サイトの見方はこうです——入力について本当に問うべきは「この値は正しいか」ではなく「この入力に、どこまで決めさせているか」。
値だけを決めさせているのか。構造も決めさせているのか(プロトタイプ汚染)。型も決めさせているのか(本記事)。置き場所まで決めさせているのか(ファイルアップロードの脆弱性)。外部に渡している決定権を数えると、危険な箇所は自然に浮かび上がります。
出典(一次情報)
- OWASP Cheat Sheet Series「Deserialization Cheat Sheet」 — cheatsheetseries.owasp.org(影響の3類型、純粋なデータ形式への切り替え、署名による整合性検証、言語別の注意点、
BinaryFormatterについての記述は、いずれもこの文書にもとづきます。2026-09-05に確認)
次に読む
- 同じ構図:プロトタイプ汚染(Node.js)(外部データが「構造」を決める) / ファイルアップロードの脆弱性(外部データが「置き場所」を決める)
- 用語:リモートコード実行(RCE)とは
- 依存:osv-scannerの導入と使い方 / CVE対応の実務手順
よくある質問
Qデシリアライズの何がそんなに危険なのですか? ただのデータ変換では?
形式によっては、データ変換ではなく『オブジェクトの再構築』だからです。どのクラスのインスタンスを作るかという情報まで外部データに含まれる形式では、攻撃者は『何を作らせるか』を選べます。OWASPは、デシリアライザに対する攻撃がサービス停止、アクセス制御の迂回、そしてリモートコード実行を許すことが判明していると述べています。値の妥当性を検証しても、値を受け取る前の段階で決着がついてしまう点が厄介です。
Qいちばん確実な対策は何ですか?
外部から来るデータを、型を選べない形式に限定することです。OWASPは『JSONやXMLのような純粋なデータ形式に切り替えることで、独自のデシリアライズ処理が悪意ある目的に転用される可能性を減らせる』としています。そのうえで、どうしても独自形式が必要なら『シリアライズの過程で署名し、認証された署名を持たないメッセージはデシリアライズしないという選択ができる』とも書かれています。形式を変える、それが無理なら署名で縛る、という順番です。
Q設定を固めれば安全に使えますか?
仕組みによります。OWASPは .NET の BinaryFormatter について『この型は危険であり、安全にすることはできない』と明言しています。つまり一部の機構は、設定や検証の追加では安全にならず、使用をやめる以外の解決がありません。設定で守れるものと、そもそも守れないものを分けて考えてください。『正しく使えば大丈夫』が成り立たない道具は実在します。
Q自分の言語では何に気をつければいいですか?
OWASPが名指ししているものだけでも、PHPでは unserialize() を避けてJSONを使うこと、Pythonでは pickle / c_pickle、PyYAML の load、jsonpickle が危険であること、JavaではObjectInputStreamのresolveClassをオーバーライドして復元できるクラスを制限すること、.NETではBinaryFormatterを使わないことが挙げられています。共通しているのは『言語の便利な永続化機構ほど、外部データに向けてはいけない』という点です。