web-dev-qa-db-ja.com

パストラバーサル攻撃を防ぐ最善の方法は何ですか?

Javaサーバーの実装(重要な場合はTFTP)を使用していて、パストラバーサル攻撃の影響を受けないようにして、利用できないはずのファイルや場所にアクセスできるようにしたい。

これまでの最善の防御策は、File.isAbsolute()に一致するエントリを拒否し、File.getCanonicalPath()を使用して../および./コンポーネントを解決することです。道。最後に、結果のパスがサーバーの必要なルートディレクトリ内にあることを確認します。

public String sanitize(final File dir, final String entry) throws IOException {
    if (entry.length() == 0) {
        throw new PathTraversalException(entry);
    }

    if (new File(entry).isAbsolute()) {
        throw new PathTraversalException(entry);
    }

    final String canonicalDirPath = dir.getCanonicalPath() + File.separator;
    final String canonicalEntryPath = new File(dir, entry).getCanonicalPath();

    if (!canonicalEntryPath.startsWith(canonicalDirPath)) {
        throw new PathTraversalException(entry);
    }

    return canonicalEntryPath.substring(canonicalDirPath.length());
}

これが見逃すセキュリティ問題はありますか?同じ結果を確実に達成するためのより良い/より速いですか?

コードはWindowsとLinuxで一貫して動作する必要があります。

38
Rob Oxspring

以下が役立ちます。正規パスと絶対パスを比較し、それらが異なる場合は失敗します。 Mac/Linuxシステムでのみテストされています(つまり、ウィンドウはありません)。

これは、ユーザーが絶対パスではなく相対パスを指定できるようにし、親ディレクトリの参照を許可しない場合に使用します。

public void failIfDirectoryTraversal(String relativePath)
{
    File file = new File(relativePath);

    if (file.isAbsolute())
    {
        throw new RuntimeException("Directory traversal attempt - absolute path not allowed");
    }

    String pathUsingCanonical;
    String pathUsingAbsolute;
    try
    {
        pathUsingCanonical = file.getCanonicalPath();
        pathUsingAbsolute = file.getAbsolutePath();
    }
    catch (IOException e)
    {
        throw new RuntimeException("Directory traversal attempt?", e);
    }


    // Require the absolute path and canonicalized path match.
    // This is done to avoid directory traversal 
    // attacks, e.g. "1/../2/" 
    if (! pathUsingCanonical.equals(pathUsingAbsolute))
    {
        throw new RuntimeException("Directory traversal attempt?");
    }
}
6
Brad Parks

ファイル名で許可されている文字( http://en.wikipedia.org/wiki/Filename )をチェックアウトして、許可されていないすべての文字(ホワイトリスト)をフィルターで除外すると、次のことが確実になります。そこにファイル名があります。

0
Tower