Aaron Digulla Aaron Digulla - 1 month ago 7
Java Question

Secure way to create relative java.io.File

How do I create a

java.io.File
instance relative to a parent folder in a secure way, i.e. preventing a malicious attacker from breaking out of the parent folder.

Example:

String path = request.getParameter( "path" );
File file = new File( folder, path );


this is unsecure since the attacker might send me a
../../../etc/passwd
as
path
.

How do I "clean" such a path?

Answer

After reading the other answers, I came up with this solution:

public static boolean isParent( File parent, File file ) {

    File f;
    try {
        parent = parent.getCanonicalFile();

        f = file.getCanonicalFile();
    } catch( IOException e ) {
        return false;
    }

    while( f != null ) {
        // equals() only works for paths that are normalized, hence the need for
        // getCanonicalFile() above. "a" isn't equal to "./a", for example.
        if( parent.equals( f ) ) {
            return true;
        }

        f = f.getParentFile();
    }

    return false;
}

So the usage would be:

File file = new File( folder, path );
if( ! isParent( folder, file ) ) {
    ... deny access ...
}

The code above probably isn't very fast but all other solutions have security concerns:

  • I could remove /../|^../|/..$ but that wouldn't work on Windows. For Windows, the pattern would become more complex and don't forget that Java accepts / as file separator on Windows (yes, C:/Windows/ is valid and means the same as C:\Windows\)

    Also, the path a/../b/c is valid since it doesn't break the boundary, so just removing the relative movements isn't good enough.

  • I could create two strings using getCanonicalPath() and make sure the parent path is a prefix of file. But then, I'd have to make sure the character after the parent path is a file separator (see above why File.SEPARATOR isn't enough).

Comments