如何java.io.File
以安全的方式创建相对于父文件夹的实例,即防止恶意攻击者突破父文件夹。
例子:
String path = request.getParameter( "path" );
File file = new File( folder, path );
这是不安全的,因为攻击者可能会向我发送../../../etc/passwd
as path
。
我如何“清理”这样的路径?
在阅读了其他答案后,我想出了这个解决方案:
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;
}
所以用法是:
File file = new File( folder, path );
if( ! isParent( folder, file ) ) {
... deny access ...
}
上面的代码可能不是很快,但所有其他解决方案都有安全问题:
我可以删除/../|^../|/..$
,但这在 Windows 上不起作用。对于 Windows,该模式会变得更加复杂,不要忘记 Java 接受/
Windows 上的文件分隔符(是的,C:/Windows/
有效且含义与 相同C:\Windows\
)
此外,路径a/../b/c
是有效的,因为它不会打破边界,所以仅仅消除相对运动是不够的。
我可以使用创建两个字符串getCanonicalPath()
并确保parent
路径是file
. 但是,我必须确保父路径之后的字符是文件分隔符(见上文为什么File.SEPARATOR
还不够)。
一种解决方案是禁止任何以我猜“安全/正确”的方式是在启用(JVM)安全管理器的情况下运行您的应用程序,并禁止在预定义配置之外访问文件。但是启用安全管理器需要一些工作来确定能够运行游览应用程序所需的所有权限。/
or开头的内容..
。但
显然,操作系统文件权限也很重要。
编辑
根据要求添加了一个示例。示例来自部署在 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);
}