LoginSignup
1
1

More than 3 years have passed since last update.

Effective Java 第3版 85項 Javaのシリアライズよりも代替手段を選ぶ

Posted at

Javaでシリアライズを扱う機会があったので、Effective Java 第3版 12章を読みました。
まとめを記載します。

シリアライズ/ディシリアライズ(Serialize/Deserialize)とは

オブジェクトをバイトストリームとして符号化する、また反対にオブジェクトを再構築する手法。
Javaのフレームワークでは、オブジェクトにSerializableインターフェースを実装することによって容易に実装できる。

例えば、以下の様にUserをシリアライズ化した場合、インスタンス化されたUserオブジェクトはObjectInputStream#readObject()を呼び出せば、容易にディシリアライズされる。

public class User implements Serializable {
    private static final long serialVersionUID = 199035831519635924L;
    private String name;
    private String cardNumber;

    public User(String name, String cardNumber) {
        this.name = name;
        this.cardNumber = cardNumber;
    }
}

シリアライズの危険性

シリアライズは便利だが、上記の例では、どこからでもUserインスタンスはディシリアライズできるということにもなる。

こうしたコードは、リモートコード実行(RCE)やDoS攻撃などの攻撃の弱点になってしまう。
さらに、RMI,JMX,JMSといった、よく使われているJavaのサブシステム、およびサードパーティーのライブラリにもシリアライズは使用されているため、攻撃対象領域は広くなってしまう傾向にある。
(こうしたライブラリや製品など様々な場所で使われているJavaのシリアライズ可能な型を持つメソッドをガジェットと呼ぶ。こうしたガジェットを組み合わせることで(ガジェットチェーン)、攻撃者はネイティブコードを呼び出せてしまう。)

また、ガジェットなしでも、シリアライズ技術を利用し、DoS攻撃が仕掛けられるで「ディシリアライズ爆弾」なども作ることができてしまう。
これは、インスタンスのディシリアライズをする場合、そのフィールドや要素のハッシュコードを計算する必要があることを悪用し、例えば深い入れ子構造になっているHashSetインスタンスなどを作成してディシリアライズさせることで、莫大な計算時間を掛けさせる攻撃手法である。

ディシリアライズ攻撃に対する対応策

最善策は、システム内で一切のディシリアライズを行わないこと。
世の中には、クロスプラットフォーム構造化データ表現(≠シリアライズシステム)があり、これらを利用することで、シリアライズ以外の方法で、オブジェクトとバイトシーケンス間の変換を安全に行うことができる。
こうした表現は、基本データ型と配列のみをサポートし、Javaのシリアライズよりもはるかに単純である。

主なものに、JSONとprotobufがあり、これらは言語中立である。
・JSON→Webでよく使われる軽量のデータ交換フォーマット。JavaScript用に開発され、テキストで人間が読める形式でデータ表現ができる。
・protobuf→Googleにより、C++様に開発された。バイナリ形式で、より効率的である。

次に、既存のJavaシステムを開発している場合などで、シリアライズの利用が避けられない場合の策としては、信頼していないバイトストリームのディシリアライズは、一切行わないこと。
(特に信頼していない元からのRMI要求を受け付けないこと)
→Javaのセキュアコーディングガイドラインにて、「信頼されないデータのディシリアライズは、本質的に危険であり、避けるべきである」という記載があり、ガイドライン全体で唯一大文字・太字・斜体・赤字で強調記載されている。
Secure Coding Guidelines for Java SE

シリアライズが避けられず、データの安全性を確保できない場合は、Java9で導入されたObjectInputFilterを使用することも必要。
これにより、データストリームに適用されるフィルタ処理を、ディシリアライズ前に実行できる。
なお、フィルタ方法には以下の二種類がある。
ブラックリスト・・・デフォルトでクラスを受け入れ、潜在的に危険なクラスを拒否する方法
ホワイトリスト・・・デフォルトでクラスを拒否し、安全なクラスを受け入れるする方法

ブラックリストは、新たな脅威に対応できないため、ホワイトリストを選ぶこと
(Serial Whitelist Application Trainerとよばれるツールを使うと、ホワイトリストを自動準備し、過剰なメモリ使用や、深い構造のオブジェクトを防いでくれる。ただし、防ぐことができないディシリアライズ爆弾などの攻撃もある。)

参考図書

Effective Java 第3版

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1