圧縮ファイル圧縮解除時のパストラバーサル脆弱性の対応

圧縮ファイルの圧縮解除処理でパストラバーサルの脆弱性を招く問題とその対応について説明します。

問題

圧縮ファイルの圧縮解除処理で、パストラバーサルの脆弱性を含むコードは以下になります。

上のコードはZIPファイルを読み込み、指定先に圧縮解除する処理の一部です。脆弱性のある箇所は圧縮されているファイルのファイル名と圧縮解除先のディレクトリのパスから、ファイルを作成している以下のコードです。

上のコードですとファイル名に「../」の文字を含んでいる可能性があります。その場合は作成されるファイルのパスは、圧縮解除先のディレクトリより上の階層になります。
例として、

ですと作成されるファイルのパスは

となり、圧縮解除先のディレクトリより上の階層になります。

対応

コードの修正はGoogleヘルプの「Fixing a Zip Path Traversal Vulnerability」のページを参考に行いました。修正としては、作成したパスを正規化し、正規化したパスに圧縮解除先のディレクトリのパスが含まれているかを確認します。修正したコードは以下になります。

修正したコードでは脆弱性を含んでいた箇所を以下のように修正し、パスを正規化しています。

getCanonicalFileメソッドで正規化したパスを持つFileインスタンスを取得します。その直後に以下の処理を追加し、正規化したパスに圧縮解除先のディレクトリのパスが含まれているかを確認します。

startsWithメソッドを使用し、正規化したパスの先頭が圧縮解除先のディレクトリのパスと一致していことを確認しています。正規化したパスに、ディレクトリのパスが含まれている場合は残りの処理を実行します。パスが含まれていない場合はエラーを返します。
この修正により、以下のパスは圧縮解除でき、

以下のようなパスはエラーになります。

この対応ではパスを正規化してパスの確認をしていますので、圧縮解除先のディレクトリとその下の階層のみに制限できます。ただ圧縮ファイル内のファイル名が絶対パスについての考慮は、別の機会に試したいと思います。

参考URL
https://support.google.com/faqs/answer/9294009