【问题标题】:Securely enforcing user-input file paths within subdirectories在子目录中安全地执行用户输入文件路径
【发布时间】:2010-11-22 05:31:24
【问题描述】:

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

例如,

Path.Combine(_myRootFolder, _myUserInput)

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

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

从用户那里得到类似“/back/to/myrootfolder/../../and/out/again”的东西。对此有何策略?我是否错过了一种我可以使用的非常明显的 .NET 方法?

【问题讨论】:

    标签: c# file security directory


    【解决方案1】:

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

    所以请谨慎使用此方法!

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

        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() 方法。请使用那个代替上面的代码。

    【讨论】:

      【解决方案2】:

      在 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 然后检查它的开头是否与您要锁定的目录匹配。

      【讨论】:

      • 是的,这就是我想要的那种功能......但不幸的是,我在一个 Windows 服务中,它正在将一堆文件从一个地方批量上传到另一个地方。
      【解决方案3】:

      我相信 Path.FullPath 会做你需要的(虽然我没有测试过):

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

      【讨论】:

        【解决方案4】:

        嗯,在您的 FTP 服务器示例中,您应该适当地设置用户的主目录和权限,这样他们就无法离开该文件夹。你有什么理由不能这样做?

        【讨论】:

          【解决方案5】:

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

          【讨论】:

          • 我希望避免的是依赖我自己对路径快捷方式的了解。 “../”绝对是向上移动的唯一方法吗?例如,您能否使用奇怪的 unicode 字符进行 URL 类型编码技巧....如果可能的话,我宁愿在文件路径完全未转义后进行检查?
          猜你喜欢
          • 1970-01-01
          • 2019-01-05
          • 2018-09-18
          • 1970-01-01
          • 1970-01-01
          • 2021-06-29
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多