Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 851
Aaron Digulla Avatar asked Apr 24 '13 07:04

Aaron Digulla


2 Answers

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).

like image 66
Aaron Digulla Avatar answered Oct 15 '22 19:10

Aaron Digulla


One solution would be to disallow anything that starts with / or ... But I guess the "secure/proper" way is to run your application with a (JVM) security manager enabled and disallow file access outside the predefined configuration. But enabling a security manager requires some work figuring out all the permissions you need to be able to run tour application.

OS file permissons are also important, obviously.

Edit

Added an example, as requested. Example is from a current project deployed in Tomcat:

grant codeBase "file:${catalina.base}/webapps/mywebapp/-" {
    permission java.io.FilePermission "path/to/folder", "read"; // Anything else will be disallowed
    // Other required permissions
}
like image 31
NilsH Avatar answered Oct 15 '22 19:10

NilsH