【问题标题】:PHP: Recommended way to escape slashes in path (e.g. to prevent directory traversal attack)PHP:在路径中转义斜杠的推荐方法(例如,防止目录遍历攻击)
【发布时间】:2016-06-11 20:21:22
【问题描述】:

我正在寻找一个 PHP 函数来将字符串清理为安全有效的文件名,并且没有目录分隔符(斜杠)。

理想情况下,它应该是可逆的,并且不应过度扰乱名称。

当然我想防止故意的目录遍历攻击。但我也想防止创建子文件夹。

我认为urlencode() 会起作用,但我想知道这是否足够,和/或是否有更好或更受欢迎的东西。

此外,如果有一些东西在 Windows 上同样有效(反斜杠作为目录分隔符) - 那么该解决方案将是可移植的。

用例/场景:

作为数据导入的一部分,我想将文件从远程 url 下载到本地文件系统。网址来自 csv 文件。它们中的大多数都可以,但它们可能包含比预期更多的斜线。

例如大部分都是这样的:
https://files.example.com/pdf/12345.pdf

但是个别文件可能是这样的:
https://files.example.com/pdf/1/2345.pdf

所有文件都应该放在同一个目录中,例如 https://files.example.com/pdf/12345.pdf -> /destination/dir/12345.pdf

1/2345.pdf 之类的文件不应生成子目录。相反,/ 应该以某种(可逆)方式转义。例如。使用 urlencode() 这将是 1%2F2345.pdf

【问题讨论】:

  • 您还有其他要求吗?可读性?双向转换? (即从文件名中获取原始 URL?)许多其他人也使用 URL 编码。
  • “理想情况下它应该是可逆的,并且不应过度扰乱名称”-原始问题的一部分:)
  • 一个好的答案不仅对我有用,对其他访问者也有用。它可以首先关注可逆情况(其中 urlencode() 可能是首选的解决方案),然后为要求略有不同的人提出一个或多个替代方案。
  • 而且,只是说:“可逆”解决方案还具有防止名称冲突的优点。
  • 刚刚更新了我的答案,看看

标签: php escaping directory-traversal


【解决方案1】:

您可以创建一组替换。例如,您可以使出现在文件名中的 / 字符用“(斜杠)”之类的其他内容表示。只需使用 str_replace 在查找文件名和将文件名编码为 url 之间切换。这只是一个例子。

【讨论】:

    【解决方案2】:

    这应该对你有帮助。

    输入https://files.example.com/pdf/1/2345.pdf

    输出:pdf_1_2345.pdf

    $url = 'https://files.example.com/pdf/1/2345.pdf';
    $parse = parse_url($url);
    
    //get path, remove first slash
    //$path: pdf/1/2345.pdf
    $path = substr($parse['path'],1);
    
    //result becomes: pdf_1_2345.pdf
    $result = str_replace('/','_',$path);
    

    编辑: 最好的办法是将远程文件 url 存储在数据库中,对其值进行哈希处理(使用 md5 或类似名称)并在本地以该名称保存文件,将该哈希值也存储在数据库中.

    这是您最好的选择,这样您就可以始终知道哪个远程文件对应于您的本地文件,反之亦然,并且您不必在本地处理文件名,因为它们可以是您想要的任何文件(只要当您检查它们的唯一性时)

    Database Table:
    --------------------
    | id | remote_url                  | local_name     |
    -----------------------------------------------------
    | 1  | http://example/.../123.pdf  | sdflkfd..dl.pdf|
    

    你明白了。

    【讨论】:

    • str_replace() 是不可逆的,但它是一个有效的解决方案。我不知道谁是第一个这样做的,所以对两者都 +1。
    • 如果你喜欢我的回答,请采纳。t
    • 哦,我明白了,为了可逆,只需使用唯一字符串而不是 .. 如果该文件名中存在该唯一字符串,您会自动选择另一个。选择了 _=DIR= 之类的东西,我敢肯定没有文件名会这样:)) 但它是一个有效的名称。
    • 是什么让任何一个字符串比另一个更独特?如果文件中也存在第二个字符串,我该怎么办?我在开玩笑,但如果你坚持下去,你会得到类似于已经存在的可逆字符串转换的东西。
    • 没有人会像我上面发布的那样有一个字符串,如果你超级疯狂,一旦你有所有的网址,你可以检查那个字符串,如果它存在你简单地选择另一个并检查(通过在该字符串的末尾添加任意字符),我很确定您不会在任何文件名中包含一些疯狂的 =DIR=
    【解决方案3】:

    您可以使用此功能,它将所有目录分隔符替换为下划线。

    function secureFilePath($str)
    {
        $str = str_replace('/', '_', $str);
        $str = str_replace('\\', '_', $str);
        $str = str_replace(DIRECTORY_SEPARATOR, '_', $str); // In case it does not equal the standard values
        return $str;
    }
    

    【讨论】:

      猜你喜欢
      • 2015-01-20
      • 2019-10-15
      • 1970-01-01
      • 1970-01-01
      • 2011-05-11
      • 1970-01-01
      • 2013-10-27
      • 1970-01-01
      相关资源
      最近更新 更多