PHP文件上传安全-保留原始文件名

teu*_*eum 2 php security filenames file-upload

我想允许网站(PHP)的注册用户上传文件(文档),这些文件将可供公开下载。在这种情况下,我保留文件的原始名称是一个漏洞吗?如果是的话,我想知道为什么,以及如何摆脱它。

pin*_*hic 6

虽然这是一个老问题,但在查找“安全文件名”时,它在搜索结果列表中的排名出人意料地高,因此我想扩展现有的答案:

是的,这几乎肯定是一个漏洞。

如果您尝试使用原始文件名存储文件,则可能会遇到几个可能的问题:

  • 文件名可以是保留的或特殊的文件名。如果用户上传一个名为 的文件,.htaccess告诉网络服务器将所有.gif文件解析为 PHP,然后上传一个.gif带有 GIF 注释的文件,会发生什么情况<?php /* ... */ ?>
  • 文件名可以包含../. 如果用户上传名为 'name' 的文件会发生什么../../../../../etc/cron.d/foo?(这个特定的示例应该由系统权限捕获,但是知道系统从中读取配置文件的所有位置吗?)
    • 如果 Web 服务器运行的用户(我们称之为www-data)配置错误并且拥有 shell,那又如何呢../../../../../home/www-data/.ssh/authorized_keys?(同样,这个特定的示例应该由 SSH 本身(并且可能不存在的文件夹)来防范,因为该authorized_keys文件需要非常特殊的文件权限;但是如果您的系统设置为默认提供限制性文件权限(棘手!),那么这就不是问题了。)
  • 文件名可以包含x00字节或控制字符。系统程序可能不会按预期响应这些命令 - 例如,一个简单的ls -al | cat(不是我知道你为什么要执行它,而是一个更复杂的脚本可能包含最终归结为此的序列)可能会执行命令。
  • .php一旦有人尝试下载该文件,文件名可能会以 结尾并被执行。(不要尝试将扩展程序列入黑名单。)

处理这个问题的方法是自己滚动文件名(例如,md5()在文件内容或原始文件名上)。如果您绝对必须尽最大努力允许原始文件名,请将文件扩展名列入白名单,对文件进行MIME 类型检查,并将文件名中可以​​使用的字符列入白名单

或者,您可以在存储文件时自行滚动文件名,并在人们用来下载文件的 URL 中使用(尽管如果这是一个文件服务脚本,您应该避免让人们在这里指定文件名,无论如何,所以不下载您../../../../../etc/passwd或其他感兴趣的文件),但将原始文件名存储在数据库中以便在某处显示。在这种情况下,您只需担心 SQL 注入和 XSS,这是其他答案已经涵盖的基础。