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

wixjitnu  于 2023-04-28  发布在  PHP
关注(0)|答案(3)|浏览(114)

已关闭,此问题需要更focused。目前不接受答复。
**想改善这个问题吗?**更新问题,使其仅通过editing this post关注一个问题。

两年前关闭。
Improve this question
为了保护我们正在编程的网站免受SQL注入或XSS等攻击,我们需要在存储或显示用户的输入之前对其进行过滤。
在PHP中,我们使用htmlspecialcharsaddslashes函数来防止XSS和SQL-Injection攻击。那么,那些文件呢?
我曾经通过检查文件类型和扩展名来保护网络应用程序,以了解这些文件是否在白名单中。但是我不使用htmlspecialcharsaddslashes函数,因为我没有看到有人使用这种方法。
例如,如果我想获取使用$_FILES['file']['tmp_name']的文件名,那么我将其直接存储到数据库中。
这是错误的,还是它不能注入代码,命令。..等等

c0vxltue

c0vxltue1#

    • 在处理$_ FILES ['file ']之前,我需要过滤它吗?**

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

长回答:

我曾经通过检查文件类型和扩展名来保护网络应用程序,以了解这些文件是否在白名单中。
这是一个很好的方法,如果正确应用和执行。
$_ FILES数组只是一个 * 载体 。它本身不能被滥用,但你必须 * 信任 * 它所携带的东西-即信任正在传递给服务器/由服务器传递的文件。
当我写下这个答案的时候;下面;似乎OP对他们实际上在保护什么以及为什么感到困惑:
OP称之为“最佳实践”(
绝对不是 ):
如果你想使用$_ FILES ['file '] ['tmp_name']来存储到你的数据库中或者显示在你的UI中,你应该使用addslashes或者PDO prepare语句来保护你免受SQL-Injection攻击。
这是对$_FILES数组填充方式的误解。$_FILES['file']['tmp_name']的值是由服务器
**设置的,而不是由用户或客户端设置的。
用户给定的值为:

$_FILES['file']['name']
$_FILES['file']['type']
$_FILES['file']['size']
    • 这些是需要检查的字符串值。只要您不信任这些字符串值,就没有什么可担心的。**

将文件存储在数据库中是not usually a good idea,并且在数据库安全性方面有自己的缺陷,dhnwebpro has their own answer
$_FILES['file']['tmp_name']是临时存储空间中文件的服务器位置。
PHP Manual明确指出:
默认情况下,文件将存储在服务器的默认临时目录中,除非php中的upload_tmp_dir指令指定了另一个位置。服务器的默认目录可以通过在PHP运行的环境中设置环境变量TMPDIR来更改。
如果该文件没有被移走或重命名,则将在请求结束时从临时目录中删除。

  • 如果你认为你的$_FILES['file']['tmp_name']值被滥用了,那么这是服务器妥协的迹象,你的盘子里有一大堆麻烦,远远超过了恶意的文件上传。*

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

有许多类型的文件攻击,这个主题远远超出了您所问的范围。比如说;真正的JPEG图像可以在JPEG元数据中包含XSS脚本,但当加载和查看JPEG时会触发此XSS,但对于未专门检查此漏洞 * 的外部观察者 * 而言,JPEG文件并非“坏文件”或XSS文件。
那么,你是阻止这个file.jpg还是阻止 * 所有 * Jpeg文件?这是一个艰难的决定,但在PHP中有一些非常好的工作方法(我相信这也超出了这个问题的范围)。简而言之,你的问题可以做一些编辑和澄清,你到底想保护什么,你愿意走多远达到保护水平。
我可以给你一个粗略的全面指导,以防止某些 * MIME文件类型 * 被接受到您的服务器上。这看起来和感觉像你想要的,一些东西来阻止偷偷摸摸的MP4视频被上传为文档文件(反之亦然)。

一:

忽略文件名($_FILES['file']['name'])。* * 切勿**信任用户数据。

  • 编辑:正如meagar所指出的,您可能需要保留原始文件名,在这种情况下,您应该使用REGEX或类似工具检查它以删除不需要的字符。..*

二:

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

三:

使用PHP Finfo函数集作为初步指标。它是**不完美,但会抓住大多数东西。

$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:图片:

如果你正在检查上传的图像,最好的方法是按照3检查finfo文件类型,然后让PHP将图像加载到空白画布中并重新保存图像,从而剥离所有多余的元数据和其他可能不需要的非图像数据数据。
Like this method: Remove exif data from jpg using php

五:

另外,建议您始终为上传的文件指定随机名称,永远不要使用$_FILES['file']['name']值。

六:

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

sq1bmfud

sq1bmfud2#

有一个函数is_uploaded_file来确定文件确实是一个上传的文件,而不是用户对文件路径的某种操作。据我所知,is_uploaded_file($_FILES['file']['tmp_name'])不可能返回false。您还应该检查filesize($_FILES['file']['tmp_name'])是否小于要插入的列的大小。
至于“直接存储到数据库”,你仍然需要practice good SQL injection prevention文件内容。此外,通常很难扩展在数据库中存储文件的解决方案,但这是一个您可能已经考虑过的单独问题。

w8rqjzmb

w8rqjzmb3#

如果你使用的是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不会有什么坏处。

相关问题