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

悪魔の招待状を見抜く:不安全なデシリアライズという「見えない侵入」の正体

こんにちは!現場で泥臭いインシデント対応を続けていると、たまに「なぜそんなところから?」と首を傾げたくなるような攻撃に出くわします。その代表格が、今回お話しする「不安全なデシリアライズ(Insecure Deserialization)」です。

名前に少し威圧感がありますが、怖がる必要はありません。まずは身近な例えから、その仕組みを紐解いていきましょう。

「魔法の箱」が引き起こす悲劇

皆さんの家には、遠く離れた友人から届いた「中身が何かわからない箱」が届くことはありませんか?

プログラムの世界でも、データはインターネットという配送業者を通って運ばれます。その際、元のオブジェクト(データのかたまり)を、通信しやすいように「圧縮した形」に変換することをシリアライズと言い、受け取った側がそれを元の形に戻すことをデシリアライズと呼びます。

ここで問題になるのが、「中身をろくに確認せず、届いた箱をそのまま自分の家のリビングで開けてしまう」という行為です。

もし、その箱の中に「開けた瞬間に家の鍵を勝手に開けてしまう魔法」が仕込まれていたら? あるいは、「勝手に家電を操作して火事を起こすプログラム」が入っていたら?

これが、不安全なデシリアライズの正体です。攻撃者は、本来のデータに「悪意あるオブジェクト」を隠して送り込み、プログラムにそれを「信頼できるもの」として復元させることで、サーバーの乗っ取りや情報の盗み出しを狙うのです。

なぜ「中身を確認する」のが難しいのか?

開発者の皆さんはこう思うはずです。「ちゃんと型(Class)を指定しているから大丈夫じゃないの?」と。

しかし、多くの言語(特にJavaやPython)におけるデシリアライズ処理は、復元するプロセスの中で、そのクラスのメソッドが勝手に実行されてしまうという性質を持っています。つまり、箱を開けた(デシリアライズした)瞬間に、攻撃者が仕込んだプログラムが「勝手に動き出してしまう」のです。

これが、単なるデータ改ざんを超えた「コマンド実行」という致命的な脅威につながる理由です。

どうすれば「泥棒」を追い返せるのか?

では、どうやってこの危険な招待状を拒否すればいいのでしょうか。対策は「玄関での徹底した身元確認」に尽きます。

1. 基本中の基本:信頼できないデータは絶対にデシリアライズしない

最も安全なのは、そもそも「外部からのデータ」を直接オブジェクトに変換しないことです。代わりに、JSONのような「データのみ」を扱う形式を使いましょう。JSONには「動き」が含まれないため、今回のような攻撃を受けるリスクを劇的に下げることができます。

2. ホワイトリストで「入居者」を限定する

どうしてもデシリアライズが必要な場合は、「許可したクラス以外は絶対に開けない」という設定を施します。

Javaでの実装例(Look-ahead ObjectInputStreamの活用)

import java.io.;

// ホワイトリスト方式で安全にデシリアライズする例
public class SecureDeserializer extends ObjectInputStream {
public SecureDeserializer(InputStream in) throws IOException {
super(in);
}

@Override
protected Class resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException {
// 許可するクラス名だけをリストアップする(ホワイトリスト)
if (!desc.getName().equals(“com.myapp.dto.UserSession”)) {
throw new InvalidClassException(“不正なクラスへのアクセスを検知しました”, desc.getName());
}
return super.resolveClass(desc);
}
}

このように、「許可された名前(クラス)以外は受け付けない!」と玄関先でガードマンを立たせることが重要です。

3. データの改ざんを検知する

データが途中で書き換えられていないか、デジタル署名を付与するのも賢い方法です。箱に封印(署名)をしておき、届いた時にその封印が壊れていないか確認します。封印がなければ「誰かが中身をいじったな」と判断できますよね。

一歩ずつ対策を学んでいきましょう!

不安全なデシリアライズは、システムを深く理解していないと見落としがちな盲点です。しかし、今日こうして知識を得た皆さんは、もう「中身を確認せずに箱を開ける」ようなことはしないはずです。

  • 「データを渡すときは、極力JSONのような安全な形式を使う」
  • 「どうしてもシリアライズが必要なら、許可したクラスだけを通すガードマン(ホワイトリスト)を立てる」

この二つを意識するだけで、皆さんの書くコードの安全性は飛躍的に向上します。セキュリティは一度きりのイベントではなく、日々の積み重ねです。まずは今日、皆さんのアプリケーションで「ObjectInputStream」のような危険なキーワードが使われていないか、検索してみることから始めてみませんか?

これからも、安全で強固なアプリケーション作りを一緒に楽しんでいきましょう!

コメント

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