PHP 7.4 中仅靠 in_array() 做黑白名单过滤无法防御恶意文件上传,必须结合 pathinfo() 提取扩展名、finfo_file() 校验真实 MIME 类型及权限隔离才有效;黑名单已基本失效。 直接给出结论:在 PHP 7.4 环境中,若仅依靠 in_array() 函数实现的黑
PHP 7.4 中仅靠in_array()做黑白名单过滤无法防御恶意文件上传,必须结合pathinfo()提取扩展名、finfo_file()校验真实 MIME 类型及权限隔离才有效;黑名单已基本失效。

直接给出结论:在 PHP 7.4 环境中,若仅依靠 in_array() 函数实现的黑白名单来保障文件上传安全,本质上是为自己制造风险。白名单必须与 pathinfo()、finfo_file() 以及严格的权限控制组合使用,才能发挥实际作用。至于黑名单,其绕过方法众多,在 PHP 7.4 中基本已经失去防御意义。
长期稳定更新的攒劲资源: >>>点此立即查看<<<
pathinfo()很多开发者习惯使用 substr(strrchr($filename, '.'), 1) 或 explode('.', $filename) 这类“土办法”来获取文件后缀。这些方法虽然看上去简单,但在边界情况下容易出现问题:
abc.):explode 会拆分为 ['abc', ''],使用 end() 获取时得到空字符串。若白名单中没有空字符串,in_array 返回 false 倒问题不大,但若处理不当则可能导致误放行。shell.php.jpg):explode 取最后一段得到 jpg,看似合法,但如果服务器配置不当(如 Apache 解析漏洞),则存在安全隐患。shell.PHP):未统一转小写就直接比对,in_array('PHP', $whitelist) 会返回 false,导致正常文件被误拦截。因此,标准做法是使用 $ext = strtolower(pathinfo($_FILES['file']['name'], PATHINFO_EXTENSION));。这行代码能够稳定处理无扩展名、多点、大小写混杂等几乎所有的边界情况,请避免自行编写解析函数。
move_uploaded_file() 之前,且先检查 $_FILES['file']['error']常见的错误做法是“先移动后校验”——先用 move_uploaded_file() 将文件移动到目标目录,再回头检查。这会导致恶意文件已经在服务器上落地,即使后续发现也来不及删除。
error 状态:当 $_FILES['file']['error'] !== UPLOAD_ERR_OK(例如上传大小超限、部分上传等),tmp_name 可能为空或无效。后续使用 finfo_file() 读取时会抛出“failed to open stream”错误,从而暴露服务器路径。正确的防御顺序如下:
if ($_FILES['file']['error'] === UPLOAD_ERR_OK) {
$ext = strtolower(pathinfo($_FILES['file']['name'], PATHINFO_EXTENSION));
if (in_array($ext, $allowed)) {
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$mime = finfo_file($finfo, $_FILES['file']['tmp_name']);
finfo_close($finfo);
if (in_array($mime, ['image/jpeg', 'image/png'])) {
/* 生成唯一文件名 + move */
}
}
}
先校验 error,再校验后缀,然后通过 finfo_file 检查文件内容的真实 MIME 类型,最后才考虑移动文件。每一步都不能省略。
尽管 PHP 7.4 默认修复了 %00 截断漏洞,但这并不意味着黑名单变得安全。绕过思路多种多样:
.php5、.phtml、.php7 等后缀,黑名单通常难以覆盖全面,一旦遗漏即形成漏洞。.Php、.PHTML 等变体,若黑名单比对未统一转小写,即可被绕过。shell.php.)或空格(shell.php ),系统保存时会自动修剪,但黑名单检测时却认为是安全文件。Content-Type 为 image/png,若仅校验该字段,则直接中招。因此,如果在现有代码中看到类似 $blacklist = ['php', 'jsp', 'asp']; 的写法,请立即删除。它除了提供虚假的安全感之外,没有任何实际作用。
白名单只是第一道防线,通过之后还需要两条后续防线:
finfo_file() 校验真实 MIME 类型:请记住,$_FILES['file']['type'] 由浏览器发送,完全受用户控制,不可信赖。只有基于 libmagic 库读取文件二进制头的 finfo_file() 校验才真正可靠。uniqid() . '.' . $safe_ext 这类随机生成方式,绝不应拼接原始文件名。同时,上传目录不应位于 Web 根目录下。如果必须放在根目录,则需要配置 Nginx 的 location ~ .php$ { deny all; },或关闭 Apache 的 Options +ExecCGI,彻底禁止该目录的脚本执行权限。此外,如果业务涉及 PDF、Office 等文件,即使它们通过了白名单和 MIME 校验,也可能内嵌恶意宏或 JavaScript。这已经是另一个层面的问题,需要额外调用 pdfinfo 或 oletools 进行深度扫描——此时白名单已经无法管控。
侠游戏发布此文仅为了传递信息,不代表侠游戏网站认同其观点或证实其描述