Effective Java Item 85: Prefer alternatives to Java serialization
Effective Java 3rdに書かれているserializationの欠陥について
- 一部で心配されていたJavaのserializationの安全性が深刻なことがわかった。
- ObjectInputStreamのreadObjectを使っている場合、どの型でもdeserilizeできてしまう。
Apache Commons Collectionsなどのgadget chain
- サンフランシスコの鉄道会社で実際にこの脆弱性を利用した攻撃(ランサムウェア)があった。
- 2日間システム停止
- 結局バックアップから復元して身代金は払わなかったらしい。
- gadget chainと呼ばれる仕組みとdeserializationの脆弱性を組み合わせて使い、任意コードの実行ができる
- 信頼できないバイトストリームをdeserializeすると危険
deserialization bomb
- hashsetのdeserialization時にはhashcodeが実行されることを利用してDOS攻撃的ができる
- 二分木のような感じで2つのhashsetを入れ子にしたhashsetを100段の深さでつくりserializeしたバイナリをdeserializeさせる
- hashcodeが2100回実行されてサーバーに負荷がかかる
static Set bomb() { Set<Object> root = new HashSet<>(); Set<Object> s1 = root; Set<Object> s2 = new HashSet<>(); for (int i = 0; i < 100; i++) { Set<Object> t1 = new HashSet<>(); Set<Object> t2 = new HashSet<>(); t1.add("foo"); // Make t1 unequal to t2 s1.add(t1); s1.add(t2); s2.add(t1); s2.add(t2); s1 = t1; s2 = t2; } return root; }
@Test void test() { try { Set nestedSet= Bomb.bomb(); FileOutputStream fos = new FileOutputStream("tempdata.ser"); ObjectOutputStream oos = new ObjectOutputStream(fos); oos.writeObject(nestedSet); oos.close(); } catch (Exception ex) { fail("Exception thrown during test: " + ex.toString()); } try { FileInputStream fis = new FileInputStream("tempdata.ser"); ObjectInputStream ois = new ObjectInputStream(fis); Set bomb = (Set) ois.readObject();//この処理が終わらない ois.close(); // Clean up the file new File("tempdata.ser").delete(); } catch (Exception ex) { fail("Exception thrown during test: " + ex.toString()); } }
本中のコードを参考に実験してみたが、serialize時(ディスク書き込み時)は一瞬で完了したが、 deserialize時(ディスク読み込み時)は処理が終わらなかった。(javaのcpu使用率が100%になった。)
JavaのSerializationは使うな?
“There is no reason to use Java serialization in any new system you write.”
代替
- JSON
- protobuf
JSONはもともとJavaScript用に作られてprotobufはC++用に作られたもの。 protobufはバイナリデータなので普通の人は直接読めないため人が読めるようなpbtxtという形式も用意されている。
どうしてもSerializeしないといけない場合の処置
すでにSerialize機構を導入してしまっているレガシーコードで廃止が難しい場合、 java.io.ObjectInputFilterを使う。
Serializeを許す/許さないをブラックリストまたはホワイトリストを設定して運用する(ALLOWED/REJECTED) ブラックリストよりホワイトリストの方が望ましい。
ホワイトリストを作成するSerial Whitelist Application Trainer (SWAT) というツールもある。
ただし、ホワイトリストを作って運用しても上記のserialize bombの攻撃は防げない。
結論
参考
- 作者: Joshua Bloch
- 出版社/メーカー: Addison-Wesley Professional
- 発売日: 2018/01/06
- メディア: ペーパーバック
- この商品を含むブログ (3件) を見る
Effective Javaの内容とほぼ同内容