【実務・中級編】Deserialization脆弱性(不安全なデシリアライズ)の仕組みと防御策 – アプリケーションセキュリティ & 安全な開発防御ガイド

なぜ「デシリアライズ」はエンジニアを破滅させるのか? ― 現場で語られない真実

やあ。今日も本番環境のログと睨めっこしているか?

アプリケーションセキュリティの現場で、最も「静かに、だが確実に」システムを終わらせる脆弱性、それが不安全なデシリアライズ(Insecure Deserialization)だ。SQLインジェクションやXSSは教科書に載っているが、デシリアライズの悪夢は、コードの奥底で眠るオブジェクトの「復元」プロセスに潜んでいる。

今日は、なぜこの脆弱性が「RCE(リモートコード実行)への特急券」と呼ばれるのか、そしてどうすれば我々が安眠できるのかを、泥臭い実務の視点で解き明かしていこう。

1. そもそも「デシリアライズ」で何が起きているのか?

まず定義を整理しよう。シリアライズとは、メモリ上のオブジェクトを保存や転送のために「バイト列(文字列)」に変換することだ。そしてデシリアライズは、その逆。文字列を受け取り、再びメモリ上のオブジェクトに戻す処理だ。

攻撃者は、この「復元」のプロセスを悪用する。悪意あるオブジェクトをシリアライズして送りつけ、サーバー側でデシリアライズさせると、復元される過程で攻撃者が仕込んだメソッドやロジックが自動的に実行される。 つまり、我々が「ただのデータ」を読み込ませたつもりが、実は「命令」を読み込ませていた、というわけだ。

攻撃のロジック(PoCの裏側)

攻撃者は、ターゲットのライブラリ(クラスパス)内に存在する「ガジェットチェーン」を探す。これは、デシリアライズ時に自動的に呼ばれるメソッド(`__wakeup`や`__destruct`など)を起点に、最終的にコマンド実行関数(`system()`や`exec()`)へと繋がるメソッドの連鎖だ。一度これが成立すれば、WAFの裏側だろうが、認証の先だろうが、OSを支配下におくことができる。

2. 【実践】Pythonでの防御策:信頼できるデータしか信じない

Pythonの`pickle`モジュールは極めて強力だが、同時に極めて危険だ。公式ドキュメントにも「信頼できないデータはデシリアライズするな」と赤字で書いてあるはずだ。

不安全なコード(絶対に書くな)

import pickle
ユーザー入力(Cookieやフォーム値)をそのまま復元するなんて自殺行為だ
data = request.cookies.get(‘session_data’)
obj = pickle.loads(base64.b64decode(data))

セキュアな実装:JSONへの転換と型チェック

解決策はシンプルだ。「実行可能なコードを含まないデータ形式」を使うこと。 JSONは構造化データであり、メソッドは含まれない。

import json
import base64

1. pickleではなくjsonを使用する
2. 厳格なスキーマチェックを行う(pydanticなどを推奨)
def safe_load_data(raw_data):
try:
decoded = base64.b64decode(raw_data)
data = json.loads(decoded)

# 必須キーの確認と型のバリデーション
if not isinstance(data.get(“user_id”), int):
raise ValueError(“Invalid Data Structure”)

return data
except (json.JSONDecodeError, ValueError) as e:
# エラーは握りつぶさずログに残せ
logger.error(f”不正なデータ受信: {e}”)
return None

3. 【実践】PHPでの防御策:`unserialize()`を封印せよ

PHPもまた、`unserialize()`が諸悪の根源だ。PHP 7.0以降なら、`allowed_classes`オプションを使い、クラスのホワイトリスト化を行うのが最低限の作法だ。

セキュアな実装例

[“UserSession”, “Settings”]]);

if ($decoded instanceof UserSession) {
// 安全に操作可能
} else {
// 異常検知、ログ出力、セッション破棄を行う
die(“セキュリティー違反の試行を検知しました。”);
}
?>

4. 運用で守る:インフラと設計の多層防御

コードレベルの対策が万全でも、ライブラリの脆弱性は避けられない。以下の防壁を組み合わせるのが、プロの仕事だ。

  • WAFによるシグネチャ検知:
  • `O:.:.{` (PHPのシリアライズ文字列) や `\x80\x03c` (Python pickleのヘッダー) を検知してブロックするルールをAWS WAFやCloud Armorに設定せよ。
  • シリアライズデータの署名(HMAC):
  • データをクライアントに渡す際、秘密鍵で署名(HMAC-SHA256など)を付与する。デシリアライズ前に署名を検証すれば、改ざんされたデータは即座に弾ける。
  • 最小権限の原則:
  • アプリケーションを実行するOSユーザーに、`exec`や`system`の使用権限を与えない。コンテナ実行であれば、読み取り専用ファイルシステムにするのがベストだ。

最後に:セキュリティは「疑うこと」から始まる

いいか、後輩たちよ。「ライブラリがよしなにやってくれる」という考えは、脆弱性の温床だ。デシリアライズは便利だが、本質的に「信頼できない入力から実行権限を奪われるリスク」を内包している。

設計段階で、「本当にシリアライズが必要か?」と自問自答してほしい。JSONやMessagePackなど、コード実行を伴わない形式で代替できないか? それができるだけで、君たちのサービスは他の多くのサイトよりも数段堅牢になる。

何か不明点があれば、またいつでもログを持って相談に来い。コードを叩く前に、まずはその「データの通り道」が安全かどうかを確認する癖をつけろ。それが、一流のエンジニアへの近道だ。

コメント

タイトルとURLをコピーしました