サーバ側でのzipファイルの解凍等の際に、意図しないディレクトリやファイル(ディレクトリトラバーサル攻撃)へのアクセスを防ぐための検証として、絶対パスを正規化したい場合がある。
Fileクラスを使ったサンプルはあるが、Pathを使ったサンプルがなかったため、検証してみた。
検証結果
結果として次の通りでした。
検証で使ったコードは次節を参照のこと。
- Fileクラスを使う場合、File#getCanonicalPath()で絶対パスを正規化できる。File#getAbsolutePath()は正規化されず、., ..が残るので注意。
- Pathクラスを使う場合、normalize()で正規化できそうだが、相対パスで帰ってくる場合があるので、絶対パスに変換してから正規化(path.toAbsolutePath().normalize())が必要である。実在パスの検証がされても良いのであれば、path.toRealPath()を使用できる。
実在検証 パス種別 コード例 備考 不要 絶対パス path.toAbsolutePath().normalize() 相対パス path.normalize() 必要 絶対パス path.toRealPath() パスが実在しない場合、NoSuchFileExceptionがスローされる。 相対パス (該当なし)
検証コードと実行結果
検証で使ったサンプルコードや実行結果を記載します。
サンプルで使用するパスには動作確認のためにスラッシュとバックスラッシュを混在させています。
package example;
import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
public class FilePathTest {
public static void main(String[] args) throws IOException{
String str1 = "C:\\test\\work1\\.\\work1-1/..\\..\\work2";
String str2 = ".\\work1\\.\\work1-1/..\\..\\work2";
System.out.println("original : " + str1);
File f1 = new File(str1);
System.out.println("File.getPath() : " + f1.getPath());
System.out.println("File.getAbsolutePath() : " + f1.getAbsolutePath());
System.out.println("File.getCanonicalPath(): " + f1.getCanonicalPath());
Path p1 = Paths.get(str1);
System.out.println("Path.toString() : " + p1.toString());
System.out.println("Path.toAbsolutePath() : " + p1.toAbsolutePath());
System.out.println("Path.normalize() : " + p1.normalize());
System.out.println("Path.toRealPath() : " + p1.toRealPath());
System.out.println();
System.out.println("original : " + str2);
File f2 = new File(str2);
System.out.println("File.getPath() : " + f2.getPath());
System.out.println("File.getPath() : " + f2.toString());
System.out.println("File.getAbsolutePath() : " + f2.getAbsolutePath());
System.out.println("File.getCanonicalPath(): " + f2.getCanonicalPath());
Path p2 = Paths.get(str2);
System.out.println("Path.toString() : " + p2.toString());
System.out.println("Path.toAbsolutePath() : " + p2.toAbsolutePath());
System.out.println("Path.normalize() : " + p2.normalize());
System.out.println("Path.toRealPath() : " + p2.toRealPath()); // NoSuchFileException
System.out.println("Path other : " + p2.toAbsolutePath().normalize());
}
}実行結果は次の通り。
Path.toRealPath()は実行時に該当パスがないとNoSuchFileException例外がスローされます。
original : C:\test\work1\.\work1-1/..\..\work2
File.getPath() : C:\test\work1\.\work1-1\..\..\work2
File.getAbsolutePath() : C:\test\work1\.\work1-1\..\..\work2
File.getCanonicalPath(): C:\test\work2
Path.toString() : C:\test\work1\.\work1-1\..\..\work2
Path.toAbsolutePath() : C:\test\work1\.\work1-1\..\..\work2
Path.normalize() : C:\test\work2
Path.toRealPath() : C:\test\work2
original : .\work1\.\work1-1/..\..\work2
File.getPath() : .\work1\.\work1-1\..\..\work2
File.getPath() : .\work1\.\work1-1\..\..\work2
File.getAbsolutePath() : C:\jee7devkit\workspace\example\java-example\.\work1\.\work1-1\..\..\work2
File.getCanonicalPath(): C:\jee7devkit\workspace\example\java-example\work2
Path.toString() : .\work1\.\work1-1\..\..\work2
Path.toAbsolutePath() : C:\jee7devkit\workspace\example\java-example\.\work1\.\work1-1\..\..\work2
Path.normalize() : work2
Path.toRealPath() : C:\jee7devkit\workspace\example\java-example\work2
Path other : C:\jee7devkit\workspace\example\java-example\work2