通过检查文件扩展名来验证图像客户端。如果扩展有效,则将其发送到 servlet 以进行后端验证。
对于非 Windows 用户,这可能会失败,他们的文件类型不一定由文件名的扩展名决定。
添加 JS 警告说“此文件不以 .png/.gif/.jpeg/.jpg 结尾 - 你确定它是图像吗?”可能很有用,但通常不允许基于扩展的上传。
验证图像的 mime 类型并确保它是 image/jpeg、image/gif 或 image/png。
这里再次存在一些问题。在 Windows 上,MIME 类型是从注册表关联中检索的,这些关联是可变的,并不总是正确的。例如,IE 通常以 JPEG 格式发送 JPEG image/pjpeg
,Citrix 用户可能会发现它们以image/x-citrix-pjpeg
.
由于上传脚本通常不使用媒体类型,因此阅读/检查它几乎没有意义。对于这里的类型,我想说你最好的选择是忽略文件名和 MIME 类型;仅使用幻数嗅探来确定格式。
在安全方面我还应该做什么
1) 小心你使用什么名称来存储文件 - 由于目录遍历、特殊文件名和扩展名(等),逐字获取用户提交的文件名是危险的.htaccess
,.jsp
并且因为文件命名规则可能是复杂的跨平台而不可靠。
如果您想在本地文件系统上使用提供的名称,它应该是基本名称、slugified(替换除了简单字符的白名单之外的所有内容)、长度限制以及从检测到的文件类型替换/添加的扩展名。
更好的是使用完全生成的名称存储文件(例如17264.dat
,与数据库中主键为 17264 的项目相关的文件);如果您需要将其提供给具有漂亮文件名的浏览器,您可以在前端 Web 服务器或文件服务 servlet 上使用重写,使其以/images/17264/some_name.png
.
2)仅仅因为它具有图像幻数并不意味着它一定是图像,或者即使它是有效图像,它也不会同时具有不同形式的其他内容(“变色龙”文件)。
例如,二进制文件中的类似 HTML 的内容可以欺骗旧版本 IE 中狡猾的 MIME 嗅探,将其视为 HTML。类似地,Flash 可能会被欺骗以<crossdomain>
在图像中加载由 XML 设置的策略集,而 Java 可以加载也是 GIF 的小程序。
使这变得更加困难的一种方法是使用服务器端图形库加载图像,然后重新保存它,导致一轮重新压缩,这通常会使文件中的任何可解析内容出现乱码。这样做的问题是像JPEG这样的有损压缩,其中重新压缩会导致视觉质量下降。
最终的解决方案通常是放弃并将图像从完全不同的主机名提供给主站点。然后,如果攻击者设法将一些 XSS 内容放入文件中,那也没关系,因为它所在的站点上没有任何东西可以破坏,只有其他静态图像。
3) 如果您出于 (2) 或其他原因在服务器端加载图像,请确保图像大小(文件大小和宽度/高度大小)在尝试加载之前是合理的。否则,您可能会被填满内存并导致拒绝服务的减压炸弹击中。
此外,如果您这样做,请确保使您的图像库/语言(例如 Java Graphics2D
)保持最新。这些语言之前存在图像处理漏洞。