我的代码是防止目录遍历还是矫枉过正?



我想确保这足以防止目录遍历,任何建议或提示将不胜感激。目录"/wwwroot/Posts/"是唯一允许的目录。

[HttpGet("/[controller]/[action]/{name}")]
public IActionResult Post(string name)
{
if(string.IsNullOrEmpty(name))
{
return View("Post", new BlogPostViewModel(true)); //error page
}
char[] InvalidFilenameChars = Path.GetInvalidFileNameChars();
if (name.IndexOfAny(InvalidFilenameChars) >= 0)
{
return View("Post", new BlogPostViewModel(true));
}
DirectoryInfo dir = new DirectoryInfo(Path.Combine(Directory.GetCurrentDirectory(), "wwwroot/Posts"));
var userpath = Path.GetFullPath(Path.Combine(Directory.GetCurrentDirectory(), "wwwroot/Posts", name));
if (Path.GetDirectoryName(userpath) != dir.FullName)
{
return View("Post", new BlogPostViewModel(true));
}
var temp = Path.Combine(dir.FullName, name + ".html");
if (!System.IO.File.Exists(temp))
{
return View("Post", new BlogPostViewModel(true));
}
BlogPostViewModel model = new BlogPostViewModel(Directory.GetCurrentDirectory(), name);
return View("Post", model);
}

可能,但我不会认为它是防弹的。 让我们分解一下:

首先,您将已知的无效字符列入黑名单:

char[] InvalidFilenameChars = Path.GetInvalidFileNameChars();
if (name.IndexOfAny(InvalidFilenameChars) >= 0)
{
return View("Post", new BlogPostViewModel(true));
}

这是一个很好的第一步,但将输入列入黑名单是不够的。 它将阻止某些控制字符,但文档没有明确说明目录分隔符(例如 包括/(。文档指出:

从此方法返回的数组不保证包含 文件和目录中无效的完整字符集 名字。完整的无效字符集可能因文件系统而异。

接下来,您尝试确保在 path.combine 之后,您具有文件的预期父文件夹:

DirectoryInfo dir = new DirectoryInfo(Path.Combine(Directory.GetCurrentDirectory(), "wwwroot/Posts"));
var userpath = Path.GetFullPath(Path.Combine(Directory.GetCurrentDirectory(), "wwwroot/Posts", name));
if (Path.GetDirectoryName(userpath) != dir.FullName)
{
return View("Post", new BlogPostViewModel(true));
}

从理论上讲,如果攻击者传入../foo(如果/不在无效字符列表中,也许会通过上面的黑名单尝试(,那么Path.Combine应该组合路径并返回/somerootpath/wwwroot/fooGetParentFolder会返回/somerootpath/wwwroot这将是不匹配的,它会被拒绝。 但是,假设Path.Combine连接并返回/somerootpath/wwwroot/Posts/../foo。 在这种情况下GetParentFolder将返回/somerootpath/wwwRoot/Posts这是匹配项,然后继续进行。 似乎不太可能,但可能会有一些控制字符根据文档通过GetInvalidFileNameChars(),说明哪些技巧Path.Combine这些内容并不详尽。

你的方法可能会奏效。 但是,如果可能的话,我强烈建议您将预期的输入列入白名单,而不是尝试将所有可能的无效输入列入黑名单。 例如,如果您确定所有有效的文件名都将由字母、数字和下划线组成,请构建一个断言该正则表达式,并在继续之前进行检查。 测试^[A-Za-z0-0_]+$会断言这一点,并且是 100% 防弹的。

相关内容

  • 没有找到相关文章

最新更新