2011-09-06 130 views
12

我开发了一个php脚本来替换当前的脚本,这将会对各个市场/国家有很大的影响。 其他人之间的脚本提供照片上传功能。PHP图像上传安全方法

经过大量的关于这个问题的阅读后,我遵循了下面描述的方法。 我将非常感谢您对其安全性的评论。

  1. 该照片上传到网站根外的私人777文件夹中。
  2. 执行白名单扩展名检查(只允许jpgs,gifs,pngs)其他所有内容都将被删除。
  3. 使用getimagesize检查最小 - 最大尺寸和照片有效性。
  4. 检查MIME类型和文件扩展名匹配。
  5. 将上传的照片调整为标准尺寸(使用imagecopyresampled)。
  6. 将创建的文件保存为jpg。
  7. 删除原始文件。
  8. 用新的(不是随机的名字)保存照片ie img51244.jpg。
  9. 根据不可预测的算法将新照片移动到公用文件夹的变量子目录(777权限)。即,img10000.jpg将被存储在photos/a/f/0/img10000.jpgimg10001.jpg将被存储在photos/0/9/3/img10001.jpg。这是由于其他原因(使用静态内容服务的子域或使用CDN)完成的。

该脚本将在Linux专用服务器上运行。

+0

这里没有东西跳出来。除了文件夹的777权限 - 据我了解,如果它有777权限,它不是私有的。但据我所知,只有当你的服务器遭到入侵时,这才会真正起作用(这至少不会影响我的脚本) – jammypeach

+2

777听起来并不安全。可能与http://stackoverflow.com/questions/3644138/secure-user-image-upload-capabilities-in-php – ajreal

+0

相关我听起来很不错,除非是非常自由的权限。也许他们可能会有所限制?否则,这将尽我所能想到的一切,包括删除EXIF数据 –

回答

3

您还应该检查上传的文件大小,因为getimagesize有时可能会超过可用的RAM内存。假设你的脚本可能会在任何时候崩溃(例如电力下降)也是很好的,所以你应该执行一些清理程序来删除剩余的不需要的文件。

+1

php.ini中已经限制了可上载的最大文件大小。 – Maerlyn

+0

是的,但这并不意味着它足以避免超出内存限制。 –

+0

如果它超过了php.ini中的大小,你不会在'$ _FILES'中得到一个文件名 - 所以你不能检查它的大小。 – Maerlyn

-1

这是一个相当完整的方法,但我没有看到任何代码执行的预防机制。

您应该确保图像的内容永远不会被包含(包含或需要调用)或通过eval()执行。

否则,可以执行包含在文件末尾的php代码。

您也可以尝试检测图像内容中的php代码(使用file_get_contents,然后搜索例如“<?php”的正则表达式),但我无法找到100%安全的方法来消除可疑代码而不会破坏一些(有效的)图像。

+0

我不知道PHP代码如何在JPG文件中执行,除非您的服务器配置错误? –

+0

它没有意义,因为很明显,没有人会打电话评估或包含在图像上。我想不出任何人会想到这样做的场景(除非他刚开始使用PHP)。 –

+0

重新采样的照片出现后,原始文件即被删除。 它只按以下顺序使用php函数: move_uploaded_file,filesize,getimagesize,imagecreatefromjpeg,imagecopyresampled。 – Alex

4
  1. 根据定义,根据定义,具有chmod 0777的目录公开给其他登录到服务器的用户,而不是私有的。正确的权限将为700,并由apache(或您的网络服务器运行的任何用户)拥有。我不知道为什么你不会在这里使用php的默认临时目录,因为它往往不在web根目录。
  2. 白名单是一个好主意。注意要有正确的实施。例如,正则表达式/.png/实际上匹配apng.php
  3. 这一步是一个好主意。它基本上检查文件魔法。
  4. 不是绝对必要的。在前两个步骤中,我们确定扩展和文件格式是正确的。如果您需要客户端指定正确的MIME类型,则还应检查给定的MIME类型和上面确定的MIME类型是否相同。

步骤5到8与安全无关。

第9步:我假设你的网站允许每个人看到每张照片。如果情况并非如此,您应该有一个URL方案,其URL大大延长(比如图像的哈希)。

+1

(-1)777在网络可访问性方面并不意味着公共 - 这就是他所说的。而你的正则表达式的例子暗示,这是任何无论如何...和BTW EXE是一个Windows扩展...: -/ – Raffael

+0

@ Raffael1984我认为phihag知道这一点。对于*在同一个Web服务器*上的其他用户的可访问性,它仍然是公共的,*这是一个问题。但我同意第2步是不必要的,如果你做3)正确 –

+0

@ Raffael1984是真的。我不确定为什么这一步是必要的。更新了答案。 – phihag