我允许用户将文件上传到我的服务器。我将面对哪些可能的安全威胁,以及如何消除它们?
假设我允许用户从其系统或网络将图像上传到我的服务器。现在,要检查这些图像的大小,我必须将它们存储在/tmp文件夹中。有风险吗?如何将风险降到最低?
/tmp
也可以说我正在wget从用户在我的表单中上传的链接中下载图像。首先,我必须将这些文件保存在服务器中,以检查它们是否实际上是图像。另外,如果一个恶作剧者给我一个URL,而我最终却下载了一个充满恶意软件的网站,那该怎么办?
wget
首先,意识到上传文件意味着用户以各种格式为您提供 了很多 数据,并且用户对该数据具有完全控制权。对于普通形式的文本字段,这甚至是一个问题,文件上传是相同的,而且更多。第一条规则是:不信任任何一个。
通过文件上传您从用户那里得到什么:
这是文件上传的三个主要组成部分,并且都不可信。
不要信任中的MIME类型$_FILES['file']['type']。这是一个完全任意的,用户提供的值。
$_FILES['file']['type']
不要将文件名用于任何重要的事情。这是一个完全任意的,用户提供的值。通常,您不能信任文件扩展名或名称。请勿使用将该文件保存到服务器的硬盘上'dir/' . $_FILES['file']['name']。如果名称为'../../../passwd',则您正在覆盖其他目录中的文件。始终自己生成一个随机名称以将文件另存为。如果需要,可以将原始文件名作为元数据存储在数据库中。
'dir/' . $_FILES['file']['name']
'../../../passwd'
切勿让任何人或任何人随意访问该文件。例如,如果攻击者将malicious.php文件上传到您的服务器,并且您将其存储在站点的webroot目录中,则用户可以直接example.com/uploads/malicious.php执行该文件并在服务器上运行任意PHP代码。
malicious.php
example.com/uploads/malicious.php
切勿将任意上传的文件公开存储在任何地方,始终将其存储在只有您的应用程序可以访问它们的地方。
仅允许特定进程访问文件。如果应该是图像文件,则仅允许读取图像并调整其大小的脚本直接访问该文件。如果此脚本在读取文件时遇到问题,则可能不是图像文件,请对其进行标记和/或丢弃。其他文件类型也是如此。如果该文件应由其他用户下载,则创建一个脚本来提供文件以供下载,并且不执行任何其他操作。
如果您不知道要处理的文件类型,请自己检测文件的MIME类型和/或尝试让特定进程打开文件(例如,让图像调整大小的过程尝试调整假定图像的大小)。在此也要小心,如果该过程中存在漏洞,恶意制作的文件可能会利用它,从而可能导致安全漏洞(此类攻击最常见的示例是Adobe的PDF Reader)。
要解决您的特定问题:
[T]甚至检查这些图像的大小,我必须将它们存储在我的/ tmp文件夹中。有风险吗?
否。如果您不对数据进行任何处理,仅将数据存储在临时文件夹中的文件中就没有风险。数据就是数据,无论其内容如何。仅当您尝试执行数据或程序正在解析数据时才有风险,如果程序包含解析缺陷,恶意数据可能会诱使这些数据做意外的事情。
当然,在磁盘上摆放各种恶意数据比在任何地方都没有恶意数据风险更大。您永远不知道谁会来做这件事。因此,您应该验证所有上传的数据,如果未通过验证,则应尽快将其丢弃。
如果一个恶作剧者给我一个网址,而我最终下载了一个充满恶意软件的整个网站怎么办?
It’s up to you what exactly you download. One URL will result at most in one blob of data. If you are parsing that data and are downloading the content of more URLs based on that initial blob that’s your problem. Don’t do it. But even if you did, well, then you’d have a temp directory full of stuff. Again, this is not dangerous if you’re not doing anything dangerous with that stuff.