信頼できない ZIP ファイルは ZipInputStream で開いてはいけない
@Java 1.8.0
ZipInputStream
から取得した ZipEntry
の getSize()
は -1
になることがあります。
1 2 3 4 5 6 7 8 | private void read(InputStream is) throws IOException { ZipInputStream zis = new ZipInputStream(is); ZipEntry entry; while ((entry = zis.getNextEntry()) != null ) { // getSize() が -1 になることがある Log.d(TAG, entry.getName() + "'s size is " + entry.getSize()); } } |
何故なのか調べてみたところ、ZIP ファイルは末尾の Central Directory にデータ情報があるため、Stream で読みだした時はその情報が正しいか保証されてないのです1。
Wikipedia に詳しいフォーマットが載っていたので詳細はそちらを参照してください。
参考
ローカルヘッダは信用できない
ZipInputStream
の ZipEntry
が返すのは 各ローカルファイルヘッダの値であり、それらが正しい保証はありません。
また、エントリを残したまま、Central Directory から削除してしまうことも可能です。 そうなると、本来消したはずのファイルが存在するかのように扱われてしまいます。 OS のファイルシステムではよく使われる手ですが、ZIP にはそぐわない気がします2。
ZipFile を使う方が良い
ZipFile
は最初に Central Directory を見に行くようです。
自分で圧縮した物等、ある程度信頼できるものは別ですが、他者が作った ZIP ファイルは ZipFile
で開いた方が無難です。
悪意のある ZIP ファイルにも気をつける
上記は悪意はなくとも問題が起こるケースですが、悪意のある ZIP ファイルを不用意に展開してしまうと ZipFile
を使っていても問題が起こる可能性があります。
具体的には次のようなエントリを持つファイルです。
- 正規化すると展開先ディレクトリの外を指すパスになるようなファイル名を持つエントリ
- 展開処理によってシステムリソースを過大に消費するようなエントリ
以下では ZipInputStream についてのみ書いてありますが、ZipFile
も同じ問題を抱えていると言えるでしょう。
参考
0 件のコメント:
コメントを投稿