我有一个Java服务器实现(TFTP,如果它对你很重要),我想确保它不容易受到路径遍历攻击,允许访问不应该可用的文件和位置。
我到目前为止最好的防守尝试是拒绝任何与File.isAbsolute()
匹配的条目,然后依靠File.getCanonicalPath()
来解析路径中的所有../
和./
组件。最后,我确保生成的路径仍在我的服务器所需的根目录中:
public String sanitize(final File dir, final String entry) throws IOException {
if (entry.length() == 0) {
throw new PathTraversalException(entry);
}
if (new File(entry).isAbsolute()) {
throw new PathTraversalException(entry);
}
final String canonicalDirPath = dir.getCanonicalPath() + File.separator;
final String canonicalEntryPath = new File(dir, entry).getCanonicalPath();
if (!canonicalEntryPath.startsWith(canonicalDirPath)) {
throw new PathTraversalException(entry);
}
return canonicalEntryPath.substring(canonicalDirPath.length());
}
这是否存在安全问题?是否更好/更快地可靠地获得相同的结果?
代码需要在Windows和Linux上一致地工作。
答案 0 :(得分:6)
以下内容可能有所帮助。它比较了规范和绝对路径,如果它们不同,那么它就会失败。仅在mac / linux系统上测试(即没有窗口)。
这适用于您希望允许用户提供相对路径而非绝对路径的情况,并且您不允许任何父目录引用。
public void failIfDirectoryTraversal(String relativePath)
{
File file = new File(relativePath);
if (file.isAbsolute())
{
throw new RuntimeException("Directory traversal attempt - absolute path not allowed");
}
String pathUsingCanonical;
String pathUsingAbsolute;
try
{
pathUsingCanonical = file.getCanonicalPath();
pathUsingAbsolute = file.getAbsolutePath();
}
catch (IOException e)
{
throw new RuntimeException("Directory traversal attempt?", e);
}
// Require the absolute path and canonicalized path match.
// This is done to avoid directory traversal
// attacks, e.g. "1/../2/"
if (! pathUsingCanonical.equals(pathUsingAbsolute))
{
throw new RuntimeException("Directory traversal attempt?");
}
}
答案 1 :(得分:2)
如果你在unix机器上运行它(我不确定Windows是否有类似的东西,但它可能),你会想看看chroot。即使你认为你已经找到了某人推荐几个目录的所有方法,但让操作系统强制执行这一事实是很好的。
(chroot导致'/'引用其他目录,所以“/”可能是“/ home / me / project”和“/../../ ..”仍然是“/ home / me /项目”。)
编辑:
有一个chroot系统调用以及一个chroot命令行工具。我不知道Java是否有本机方法,但没有什么能阻止您使用命令行工具运行服务器。当然,这应该是尽力防止其他路径操作。
答案 2 :(得分:0)
您可以查看文件名中允许的字符(http://en.wikipedia.org/wiki/Filename),并过滤掉所有不允许的字符(白名单),然后您就可以确定在那里有文件名。