代码之家  ›  专栏  ›  技术社区  ›  Demis Palma ツ Paul Dixon

PHP文件上载中未记录的清理

  •  1
  • Demis Palma ツ Paul Dixon  · 技术社区  · 8 年前

    在处理文件上载时,根据 PHP official documentation ,应对文件名进行清理,以防目录遍历和可能的其他类型的攻击:

    // basename() may prevent filesystem traversal attacks;
    // further validation/sanitation of the filename may be appropriate
    $name = basename($_FILES["pictures"]["name"][$key]);
    

    尽管如此,我发现默认情况下,当文件名到达PHP脚本时,它已经被清理干净了。

    我有证据表明,Apache接收到恶意文件名:filename=“../file.png”,而PHP脚本在$\u FILES变量中读取经过清理的名称。

    Apache输入的低级别转储:

    mod_dumpio: dumpio_in (data-HEAP):
    --------------------------eb8b65b665870e02
    Content-Disposition: form-data;
    name="attachment";
    filename="../file.png" ← [Malicious file name]
    Content-Type: image/png
    

    PHP脚本

    echo $_FILES['attachment']['name']; ← [File name already sanitised: 'file.png']
    

    我在Apache模块和php fpm中都发现了这种行为,从5.5到7.2运行php,我必须推断php解释器在将变量传递给脚本之前会执行这种清理。

    所以,感谢PHP在我不知情和不同意的情况下为我做卫生工作。然而 (这是我的问题) 因为据我所知,这个特性是没有文档记录的,所以我想知道消毒标准/regexp/算法,以确保它满足我的需要。

    1 回复  |  直到 8 年前
        1
  •  2
  •   LSerni    8 年前

    你想看看 rfc1867.c ,这似乎是您所指的部分:

    SAPI_API SAPI_POST_HANDLER_FUNC(rfc1867_post_handler)
    

    从评论来看,似乎 basename() 用于消除虚假的反斜杠 对的 (我想可能吧) Hello\ World.txt “?”)。 但这是基于IE的行为 评论指出,它可能在将来被删除。

    所以,你不能依靠这种“消毒”来继续留在那里。

    。。。

        /* The \ check should technically be needed for win32 systems only where
         * it is a valid path separator. However, IE in all it's wisdom always sends
         * the full path of the file on the user's filesystem, which means that unless
         * the user does basename() they get a bogus file name. Until IE's user base drops
         * to nill or problem is fixed this code must remain enabled for all systems. */
    
        s = _basename(internal_encoding, filename TSRMLS_CC);
        if (!s) {
            s = filename;
        }
    
    推荐文章