【入門編】 Insecure Deserialization(安全でないデシリアライズ)の脆弱性とRCE – オフェンシブセキュリティ & リバースエンジニアリング防御ガイド

こんにちは!日々の開発やインフラの管理、本当にお疲れ様です。
新人のIT担当者の方や、「セキュリティってなんだか難しそうだな…」と感じている一般開発者の皆さんに向けて、今日のテーマをお届けしますね。

今回取り上げるのは、「Insecure Deserialization(安全でないデシリアライズ)」という、名前からしてもの凄く難しそうな脆弱性です。

「またカタカナの長い名前が出てきたよ…」と思いましたか?大丈夫です!今回は、私たちの身近にある「家の鍵と宅配便」の仕組みに例えながら、一歩ずつ優しく、そして現場で役立つ知識まで一緒に紐解いていきましょう!

—

1. 「シリアライズ」と「デシリアライズ」ってなに?(宅配便のダンボールに例えてみよう)

まずは基本の言葉から整理していきましょう。プログラムの世界では、画面で動いているデータ(オブジェクト)を、そのままではネットワーク越しに送ったり保存したりすることができません。

そこで登場するのが「シリアライズ(直列化)」です。

  • シリアライズ(荷造り):

プログラムの中で元気に動き回っているデータやオブジェクトを、ぎゅっと圧縮して「一つのダンボール箱(文字列やバイト列)」に詰める作業のことです。

  • デシリアライズ(開梱):

そのダンボール箱をネットワーク越しに受け取って、元の元気なデータやオブジェクトに「パカッと開封して復元する」作業のことです。

例えば、ネットショッピングで家具を買ったときを想像してください。椅子や机はそのままの形ではトラックに入らないので、一度バラバラにしてダンボールに詰めて(シリアライズ)自宅に届きます。そして家に着いたら、ダンボールを開けて組み立て直しますよね(デシリアライズ)。これが一連の流れです。

—

2. 泥棒が「怪しいダンボール箱」を送りつけてきたら?(脆弱性の正体)

ここで問題が発生します。もし、信頼できない悪者(攻撃者)が、「中に時限爆弾が入った偽物のダンボール箱」を、あなたの家の玄関に送りつけてきたらどうなるでしょうか?

もしあなたが、中身を確認せずに「届いたからとりあえず開けよう!」と無防備にダンボールを開封(デシリアライズ)してしまったら……家の中で爆発が起きてしまいますよね。

これが、Insecure Deserialization(安全でないデシリアライズ)の正体です。

プログラムが「これは信頼できるデータに違いない」と思い込み、中身の安全性を確かめずにデシリアライズ(開封)してしまうと、攻撃者が巧みに作り込んだ「悪意あるオブジェクト」まで一緒に復元されてしまいます。その結果、サーバー上で勝手にプログラムを実行されてしまうRCE(リモートコード実行)という、システムにとって最悪の事態を引き起こしてしまうのです。

—

3. 実際のコードで見てみよう(PHPの例)

百聞は一見にしかず。ちょっと古いシステムなどで見かける、危なっかしいPHPのコードを例に見てみましょう。

<?php
// 【危ない例】ユーザーからの入力をそのままデシリアライズしているコード
class UserSession {
    public $username = "guest";
    
    // デシリアライズ(開封)された瞬間に自動で呼ばれる魔法のメソッド
    public function __wakeup() {
        // ここで危ないコマンドを実行してしまう仕掛けが隠されているかも…?
        echo "ようこそ、 " . $this->username . " さん!";
    }
}

// ユーザーから送られてきたデータをそのまま受け取る(ここが危険!)
$userInput = $_POST['session_data'];

// 中身の安全性を確認せずに、そのままデシリアライズしてしまう!
$object = unserialize($userInput);
?>

上記のコードでは、unserialize() という関数を使って、ユーザーから送られてきた $_POST['session_data'] をそのまま復元しています。
攻撃者は、この session_data の中に「サーバーを乗っ取るための特別な命令」をこっそり仕込んで送りつけてきます。そして、PHPがそれを unserialize() した瞬間に命令が実行され、サーバーが乗っ取られてしまうのです。

恐ろしいですよね。では、私たちはどうやってこの脅威から身を守れば良いのでしょうか?

—

4. 一歩ずつ学ぶ!安全なシステムを作るための対策

防犯対策と同じで、セキュリティにも「絶対」はありませんが、しっかりと鍵をかけることで被害を防ぐことができます。実務で使える具体的な対策を見ていきましょう。

対策その1:信頼できないデータを絶対にデシリアライズしない

これが一番確実で強力な防衛策です。「家の鍵が開けっ放しなら、鍵をかけよう」ではなく、「そもそも見ず知らずの他人が送ってきたダンボールは、玄関の外で受け取りを拒否する」というアプローチです。

  • ユーザーからの入力値(フォームやクッキーなど)を直接 unserialize() しない。
  • どうしてもデータをやり取りしたい場合は、PHPの unserialize() ではなく、安全なデータ形式である json_decode()(JSON形式)を使いましょう。JSONは「データの構造」だけを伝えるため、勝手にプログラムの処理やオブジェクトが実行される心配がありません。

対策その2:どうしても使う場合は「型」を厳しくチェックする

もしシステムの都合上、どうしてもシリアライズされたデータを使わなければならない場合は、デシリアライズする前に「中身の署名(改ざんされていないかの証明)」を確認する仕組み(HMACなど)を必ず導入しましょう。

—

まとめ

今回は、Insecure Deserialization(安全でないデシリアライズ)の仕組みと、その恐ろしさ、そして基本的な対策についてお話ししました。

  • シリアライズはデータをダンボールに詰めること。
  • デシリアライズはダンボールを開封すること。
  • 中身の分からない怪しいダンボール(信頼できないユーザーからの入力)をそのまま開封すると、悪意あるコードが実行されてしまう(RCE)。
  • 対策として、危ない関数 (unserialize() など) の使用を避け、安全なデータ形式 (JSON など) を活用する。

セキュリティの対策は、最初は難しく感じるかもしれませんが、「怪しいものは中身を開けずに疑う」という現実世界の防犯意識と同じです。

日々の開発の中で、「このデータは本当に信用して大丈夫かな?」と一瞬立ち止まるクセをつけるだけで、あなたも立派なセキュア・コーダーへの第一歩を踏み出しています。一歩ずつ、確実に学んでいきましょう!

コメント

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