1

我想确保这足以防止目录遍历,并且任何建议或提示都将不胜感激。目录“/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);
    }
4

1 回答 1

0

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

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

    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/wwwrootPath.Combine/somerootpath/wwwroot/Posts/../fooGetParentFolder/somerootpath/wwwRoot/PostsGetInvalidFileNameChars()Path.Combine

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

于 2019-09-05T23:19:11.490 回答