为了账号安全,请及时绑定邮箱和手机立即绑定

在处理 $_FILES['file'] 之前我需要过滤它吗?

在处理 $_FILES['file'] 之前我需要过滤它吗?

PHP
德玛西亚99 2023-07-08 20:48:41
为了保护我们正在编程的网站免受 SQL 注入或 XSS 等攻击,我们需要在存储或显示用户输入之前对其进行过滤。在 PHP 中,我们使用htmlspecialchars和addslashes函数来防止 XSS 和 SQL 注入攻击。那么,文件呢?我曾经通过检查文件类型及其扩展名来了解这些文件是否在白名单中来保护网络应用程序。但我不使用htmlspecialcharsandaddslashes函数,因为我没有看到有人使用这种方法。例如,如果我想获取我使用的文件名$_FILES['file']['tmp_name'],那么我将其直接存储到数据库中。这是错误的还是无法注入代码、命令...等?
查看完整描述

3 回答

?
汪汪一只猫

TA贡献1898条经验 获得超8个赞

在处理 $_FILES['file'] 之前我需要过滤它吗?

简短的回答:不。它只是一堆字符串值,仅此而已。

长答案:

我曾经通过检查文件类型及其扩展名来了解这些文件是否在白名单中来保护网络应用程序。

如果正确应用和执行,这是一个很好的方法。

$_FILES 数组只是一个载体。它本身不能被滥用,但您必须信任它所携带的内容 - 即信任正在传递给服务器/由服务器传递的文件。


当我写这个答案时;以下; OP 似乎对他们实际上要防范的内容及其原因感到困惑:

OP 声明为“最佳实践”(这绝对不是):

如果您想使用 $_FILES['file']['tmp_name'] 存储到数据库中或显示在 UI 中,您应该使用 addslashes 或 PDO 准备语句来防止 SQL 注入攻击。

$_FILES这是对数组填充方式的误解。该值由服务器$_FILES['file']['tmp_name']设置,而不是由用户或客户端设置。

用户给定的值为:

$_FILES['file']['name']
$_FILES['file']['type']
$_FILES['file']['size']

这些是需要审查的字符串值。只要您不信任这些字符串值,就无需担心。


在数据库中存储文件通常不是一个好主意,并且有其自身的陷阱, dhnwebpro对于这个问题(关于数据库安全)


$_FILES['file']['tmp_name']是文件在临时存储空间中的服务器位置。

PHP手册明确指出:

默认情况下,文件将存储在服务器的默认临时目录中,除非在 php.ini 中使用 upload_tmp_dir 指令指定了另一个位置。可以通过在 PHP 运行环境中设置环境变量 TMPDIR 来更改服务器的默认目录。

如果该文件尚未被移走或重命名,则该文件将在请求结束时从临时目录中删除。

如果您认为您的$_FILES['file']['tmp_name']价值被滥用,那么这是服务器受到损害的迹象,您的盘子里会遇到一大堆麻烦,远远超出了恶意文件上传的范围。


那么,如何审核正在携带的文件呢?

文件攻击有多种类型,这个主题远远超出了您所询问的范围。例如; 真正的 JPEG 图像可以在 JPEG 元数据中包含 XSS 脚本,但在加载和查看 JPEG 时会触发此 XSS,但出于所有意图和目的,JPEG 文件不是“坏文件”或不是 XSS 文件,以不专门检查此漏洞的外部观察者。

那么,您是阻止此文件file.jpg还是阻止所有Jpeg 文件?这是一个艰难的决定,但在 PHP 中,有一些非常好的解决方法(我认为这也超出了这个问题的范围)。简而言之; 您的问题可以进行一些编辑并澄清您到底想要防止什么以及您愿意在多大程度上达到该保护级别。

我可以为您提供一个粗略的包罗万象的指南,以防止某些MIME 文件类型被您的服务器接受。这看起来和感觉就像你想要的,可以阻止偷偷摸摸的 MP4 视频作为文档文件上传(反之亦然)。

1:

忽略文件名 ( $_FILES['file']['name'])。永远不要相信用户数据。

您可能需要保留原始文件名,在这种情况下,您应该使用 REGEX 或类似的命令检查它以删除不需要的字符...

2:

忽略声明的文件类型 ( $_FILES['file']['type'])。任何给定 MIME 类型的文件名(例如.pdf)都应该被忽略。永远不要相信用户数据。

3:

使用PHPFinfo函数集作为初步指标。它并不完美,但可以捕获大多数东西。

$finfo = finfo_open(FILEINFO_MIME_TYPE); // return mime type ala mimetype extension

$mimeType = finfo_file($finfo, $_FILES['file']['tmp_name']);

$whitelist = ['text/html','image/gif','application/vnd.ms-excel'];

finfo_close($finfo);

if(in_array($mimeType,$whitelist)){

    // File type is acceptable.

}

4:图片:

finfo如果您要检查上传的图像,最好的方法是按照3检查文件类型,然后让 PHP 将图像加载到空白画布中并重新保存图像,从而删除所有多余的元数据和其他可能不需要的非图像数据-数据。

像这样的方法:使用 php 从 jpg 中删除 exif 数据。

5:

还建议始终为上传的文件提供随机名称,切勿使用该$_FILES['file']['name']值。

6:

根据您试图避免和/或消除的威胁类型,您可以打开上传的文件并读取文件的前几个字节,并将其与该类型白名单文件中的已确认字节进行比较。这是非常微妙的,并且再次超出了这个答案的范围,这个答案已经足够长了。


查看完整回答
反对 回复 2023-07-08
?
浮云间

TA贡献1829条经验 获得超4个赞

有一个函数is_uploaded_file可以确定该文件确实是上传的文件,而不是用户进行的某种文件路径操作。据我所知,没有办法is_uploaded_file($_FILES['file']['tmp_name'])会返回 false。您还应该检查是否filesize($_FILES['file']['tmp_name'])小于您要插入的列的大小。

至于“直接存储到数据库”,你仍然需要对文件内容进行良好的SQL注入防护。此外,通常很难扩展将文件存储在数据库中的解决方案,但这是一个您可能已经考虑过的单独问题。


查看完整回答
反对 回复 2023-07-08
?
蝴蝶刀刀

TA贡献1801条经验 获得超8个赞

如果您使用 PDO 或 MySQLi,您应该能够将文件放在准备好的语句中,这应该可以保护您免受 SQL 注入攻击。我粘贴了https://www.mysqltutorial.org/php-mysql-blob/中的方法,其中有一些有关在 MySQL 数据库中存储文件的好信息。


/**

 * insert blob into the files table

 * @param string $filePath

 * @param string $mime mimetype

 * @return bool

 */

public function insertBlob($filePath, $mime) {

    $blob = fopen($filePath, 'rb');


    $sql = "INSERT INTO files(mime,data) VALUES(:mime,:data)";

    $stmt = $this->pdo->prepare($sql);


    $stmt->bindParam(':mime', $mime);

    $stmt->bindParam(':data', $blob, PDO::PARAM_LOB);


    return $stmt->execute();

}

或者,您可以将文件存储在文件系统上,并在需要提供文件时仅包含对该文件的引用。此方法速度更快,但不方便将所有数据保存在一处。


有关数组元素的详细信息$_FILES有点隐藏在手册中,但可以在示例 1 的末尾找到:


https://www.php.net/manual/en/features.file-upload.post-method.php


数组所有元素的值$_FILES应视为用户输入。我建议忽略这些值。但是,如果您希望将它们写入数据库和/或稍后在 UI 中显示它们,那么您肯定需要保护自己免受 SQL 注入和 XSS 攻击。因此,在这种情况下,使用准备好的语句htmlspecialchars不会有什么坏处。


查看完整回答
反对 回复 2023-07-08
  • 3 回答
  • 0 关注
  • 83 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信