简体   繁体   English

安全地创建相对java.io.File的方法

[英]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, ie preventing a malicious attacker from breaking out of the parent folder. 如何以安全的方式创建相对于父文件夹的java.io.File实例,即防止恶意攻击者突破父文件夹。

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 . 这是不安全的,因为攻击者可能会发送一个../../../etc/passwd作为path

How do I "clean" such a path? 我如何“清理”这样的路径?

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. 我可以删除/../|^../|/..$但这不适用于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\\ ) 对于Windows,模式将变得更加复杂,并且不要忘记Java接受/作为Windows上的文件分隔符(是的, C:/Windows/是有效的,意味着与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. 此外,路径a/../b/c是有效的,因为它不会破坏边界,因此仅删除相对运动是不够的。

  • I could create two strings using getCanonicalPath() and make sure the parent path is a prefix of file . 我可以使用getCanonicalPath()创建两个字符串,并确保parent路径是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). 但是,我必须确保父路径之后的字符是文件分隔符(参见上面为什么File.SEPARATOR是不够的)。

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. 我想“安全/正确”的方式是在启用(JVM)安全管理器的情况下运行应用程序,并禁止在预定义配置之外访问文件。 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. 显然,OS文件许可也很重要。

Edit 编辑

Added an example, as requested. 根据要求添加了一个示例。 Example is from a current project deployed in Tomcat: 示例来自Tomcat中部署的当前项目:

grant codeBase "file:${catalina.base}/webapps/mywebapp/-" {
    permission java.io.FilePermission "path/to/folder", "read"; // Anything else will be disallowed
    // Other required permissions
}
    String path = "../../../etc/passwd";
    String pureFilename = (new File(path)).getName();
    File file = new File(folder, pureFilename);
boolean isChild(File parent, File child) throws IOException {
    String parentCanonicalPath = parent.getCanonicalPath();
    String childCanonicalPath = child.getCanonicalPath();
    return childCanonicalPath.startsWith(parentCanonicalPath);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM