Java 检查用户请求的文件是否位于基本目录下
我在web服务器上有一个满是文件的目录层次结构,我希望用户能够通过请求访问这些文件中的任何一个。(这比这要复杂一些,这就是为什么我需要访问Java web应用程序中的文件。) 实现这一点的自然方式是允许用户指定文件,例如使用斜杠,例如Java 检查用户请求的文件是否位于基本目录下,java,Java,我在web服务器上有一个满是文件的目录层次结构,我希望用户能够通过请求访问这些文件中的任何一个。(这比这要复杂一些,这就是为什么我需要访问Java web应用程序中的文件。) 实现这一点的自然方式是允许用户指定文件,例如使用斜杠,例如/my web endpoint?param=folder1/folder2/file.txt。然后我会在Java中找到类似于newfile(baseDirectory,param)的文件。到目前为止,一切顺利 但是如果用户请求,例如,param=../someth
/my web endpoint?param=folder1/folder2/file.txt
。然后我会在Java中找到类似于newfile(baseDirectory,param)
的文件。到目前为止,一切顺利
但是如果用户请求,例如,param=../something private/file.txt
或其他什么,该怎么办?我应该如何防止这种情况
。
的参数,但这足够了吗?我总是有点担心黑名单。如果有另一种语法我没有想到呢?(例如,我想到了以/
开头的路径,但可能还有其他路径。)getCanonicalFile()
,然后检查路径是否以基本目录开始,如
File baseDirectory = ....
String param = ...
File desiredFile = new File(baseDirectory, param);
if ( ! desiredFile.getCanonincalPath().startsWith(
baseDirectory.getCanonincalPath()+File.separator))
throw ...
这是否足够?会出什么问题吗startsWith(baseDirectory.getCanonincalPath()+“/”
应该可以
更好地使用新的文件和路径类
Path path = file.toPath();
path = path.toRealPath();
// Absolute, ".." removed, sym links resolved as no param NOFOLLOW_LINKS.
path = path.normalize(); // Removes ".."
path.startsWith(baseDir); // Base path
您可以使用一种方法来检查候选路径是否以强制父路径开始。Java7NIO似乎对此有很好的支持 以下是实现此想法的方法:
/**
* Check if a candidate path starts with a mandatory parent path
* @param mandatoryParentPath Mandatory parent path
* @param candidate Candidate path which should be under the mandatory parent path
* @return {@code true} if a candidate path starts with a mandatory parent path, else {@code false}
*/
/**
* Check if a candidate path starts with a mandatory parent path
* @param mandatoryParentPath Mandatory parent path
* @param candidate Candidate path which should be under the mandatory parent path
* @return {@code true} if a candidate path starts with a mandatory parent path, else {@code false}
*/
public static boolean absoluteStartsWith(Path mandatoryParentPath, Path candidate) throws IOException {
Objects.requireNonNull(mandatoryParentPath, "Mandatory parent path should not be null");
Objects.requireNonNull(candidate, "Candidate path should not be null");
Path path = candidate.toRealPath();
System.out.println(" " + candidate); // debugging code
return path.startsWith(mandatoryParentPath.toAbsolutePath());
}
以下是验证上述方法的简单测试:
public static void main (String[] args) throws java.lang.Exception
{
Path root = Paths.get("d:/work");
System.out.println(absoluteStartsWith(root, root.resolve("/tmp")));
System.out.println(absoluteStartsWith(root, root.resolve("..")));
System.out.println(absoluteStartsWith(root, root.resolve("ems")));
}
这在我的机器上打印出来:
d:\tmp
false
d:\work\..
false
d:\work\ems
true
注意:如果其中一个候选路径不存在,那么上面的
absoluteStartsWith
方法将引发IOException。您能有效地使用权限吗?我认为文件系统权限不够。它们将阻止对系统文件的访问,但仍有web服务器用户可以访问的文件,这些文件不应公开给web。