在子目录中安全地强制执行用户输入文件路径

发布于 2024-08-02 06:23:43 字数 461 浏览 3 评论 0原文

我知道可靠的安全建议,即避免接受用户输入,然后使用该输入来选择读/写文件的路径。但是,假设您有一个想要保留的基本目录(例如 ftp 文件夹的根目录),那么如何最好地确保给定的用户输入将我们保留在该文件夹中?

例如,

Path.Combine(_myRootFolder, _myUserInput)

仍然可以将我们带到 _myRootFolder 之外。 这也可能是狡猾的

newPath = Path.Combine(_myRootFolder, _myUserInput)
if (newPath.StartsWith(_myRootFolder))
   ... 

考虑到用户提供的类似“/back/to/myrootfolder/../../and/out/again”的内容, 。对此有何策略?我是否缺少一个可以使用的极其明显的 .NET 方法?

I know the solid security recommendation of avoiding accepting user input that you then use to choose a path to read/write a file. However, assuming you have a base directory you want to keep within (such as the root of an ftp folder), how do you best ensure that a given user input keeps us within that folder?

For instance,

Path.Combine(_myRootFolder, _myUserInput)

could still take us outside of _myRootFolder. And this could also be dodgy

newPath = Path.Combine(_myRootFolder, _myUserInput)
if (newPath.StartsWith(_myRootFolder))
   ... 

given something like "/back/to/myrootfolder/../../and/out/again" from the user. What are the strategies for this? Am I missing a blindingly obvious .NET method I can use?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

溺渁∝ 2024-08-09 06:23:43

在 ASP.NET 应用程序中,您可以使用 Server.MapPath(filename) ,如果生成的路径超出应用程序根目录,它将引发异常。

如果您想要的只是一个安全的文件名,并且您只想要其中的所有文件,那么它会变得更简单;

    FileInfo file = new FileInfo(
        Server.MapPath(
            Path.Combine(@"c:\example\mydir", filename)));

如果您像您指出的那样位于 ASP.NET 之外,那么您可以使用 Path.GetFullPath

string potentialPath = Path.Combine(@"c:\myroot\", fileName);
if (Path.GetFullPath(potentialPath) != potentialPath)
    // Potential path transversal

或者您调用 Path.GetFullPath,然后检查它的开头是否与您要锁定的目录匹配。

Within ASP.NET applications you can use Server.MapPath(filename) which will throw an exception if the path generated goes outside of your application root.

If all you want is a safe file name and you just want all files in there it becomes simpler;

    FileInfo file = new FileInfo(
        Server.MapPath(
            Path.Combine(@"c:\example\mydir", filename)));

If you're outside of ASP.NET like you indicate then you could use Path.GetFullPath.

string potentialPath = Path.Combine(@"c:\myroot\", fileName);
if (Path.GetFullPath(potentialPath) != potentialPath)
    // Potential path transversal

Or you call Path.GetFullPath and then check the start of it matches the directory you want locked to.

我很OK 2024-08-09 06:23:43

我知道,这个线程已经很老了,但是为了防止后续读者编写具有潜在安全错误的代码,我想我应该指出,使用 Path.Combine(arg1, arg2) 不是当arg2直接基于用户输入时保存。
例如,当 arg2 为“C:\Windows\System32\cmd.exe”时,arg1 参数将被完全忽略,并且您向 API 或服务器应用程序的用户授予完全权限访问整个文件系统。

所以请谨慎使用此方法!

我想出了这个应该(据我所知)安全的解决方案:

    public static string SecurePathCombine(params string[] paths)
    {
        string combinedPath = "";

        foreach (string path in paths)
        {
            string newPath = Path.Combine(combinedPath, path);

            if (!newPath.StartsWith(combinedPath))
                return null;

            combinedPath = newPath;
        }

        if (Path.GetFullPath(combinedPath) != combinedPath)
            return null;

        return combinedPath;
    }

编辑: 现在有一个新的 Path.Join() 方法。请使用该代码而不是上面的代码。

I know, that this thread is quiet old, but to prevent following readers from writing code with potential security errors, I think I should point out, that using Path.Combine(arg1, arg2) isn't save when arg2 is directly based on user input.
When arg2 is for example "C:\Windows\System32\cmd.exe" the arg1 parameter will be completely ignored and you grant the users of your API or server application full access to the whole file system.

So please be very careful with using this method!

I came up with this solution that should (afaik) be secure:

    public static string SecurePathCombine(params string[] paths)
    {
        string combinedPath = "";

        foreach (string path in paths)
        {
            string newPath = Path.Combine(combinedPath, path);

            if (!newPath.StartsWith(combinedPath))
                return null;

            combinedPath = newPath;
        }

        if (Path.GetFullPath(combinedPath) != combinedPath)
            return null;

        return combinedPath;
    }

Edit: There is a new Path.Join() method now. Please use that one instead of the code above.

油饼 2024-08-09 06:23:43

我相信 Path.FullPath 会满足您的需要(但我没有测试这一点):

string newPath = Path.Combine(_myRootFolder, _myUserInput);
string newPath = Path.FullPath(newPath);
if (newPath.StartsWith(_myRootFolder)) ...

I believe Path.FullPath will do what you need (I didn't test this though):

string newPath = Path.Combine(_myRootFolder, _myUserInput);
string newPath = Path.FullPath(newPath);
if (newPath.StartsWith(_myRootFolder)) ...
蛮可爱 2024-08-09 06:23:43

好吧,在您的 FTP 服务器示例中,您应该适当地设置用户主目录和权限,以便他们无法导航出该文件夹。你有什么理由不能这样做吗?

Well, in your example of an FTP server, you should set the users home-directory, and permissions appropriately, such that they can't navigate out of the folder. Any reason you can't do that?

热情消退 2024-08-09 06:23:43

您可以解析输入字符串并使用正则表达式剪切 ../ 。

You can parse input string and cut ../ with regex.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文