删除Python中图像中的潜在恶意软件



我读过。PNG、.JPEG和其他图像文件类型可能包含恶意软件。

我正在寻找删除潜在的恶意软件嵌入用户上传的图像。Python中有没有一种方法可以从本质上"压平"图像,从而从本质上删除任何恶意内容?有点像如果你要拍一张图片的截图,然后保存截图?或者可能有一种图像类型不容易被破坏?

我已经在一个单独的域上托管了所有用户上传的内容,但我想知道我是否可以更进一步。

在最简单的级别上,位图图像包含两个内容:

  • 元数据,这是关于图像的信息,以及

  • 像素数据,其本身就是像素颜色。

元数据包含关键内容,如图像的高度和宽度、通道数、每像素的位数、图像的颜色空间以及压缩方式。它还包含可以说不那么关键的补充信息,例如:

  • EXIF数据-使用了什么相机,什么镜头,什么曝光,GPS信息等等
  • ICC色彩配置文件可实现准确的色彩再现
  • IPTC信息-新闻和电信信息、版权、主题标签等
  • 地理参考和/或摄影测量信息-请参见GeoTIFF
  • 评论-可能包含任意信息(和恶意软件)

像素数据包含组成图像的像素网格的颜色(以及可能的任何透明度)。它经常被压缩。

请注意,以上只是一个简单的层次。我只提到了位图文件,而没有提到矢量文件,如SVG文件,这些文件可能包含自己的一组问题,如"Billion Laughs DoS Attack">请参阅https://en.wikipedia.org/wiki/Billion_laughs_attack

还要注意,完全可以将整个可执行程序附加到图像的末尾或中间,而不必干扰图像读取器/显示程序,这些程序通常会忽略他们无法理解的信息,但会尽最大努力使用他们所做的部分。如果你想要一个示例,在这里,我用ImageMagick制作了一个红色图像,并将128kB的任意数据附加到末尾,并在Mac上的终端中显示,而不会受到macOS的任何投诉:

magick -size 1024x768 xc:red image.png             # make red image
dd if=/dev/zero bs=128 count=1024 >> image.png     # append 128kB of whatever I like - not actually malware in this case
open imge.png                                      # use "xdg-open" on Linux

还应注意,可以使用隐写术嵌入其他信息,例如,劫持每个像素的最低有效位,并使用它来传递消息或携带一些意外的有效载荷,如恶意软件或水印。因为它是最不重要的一点,所以通常在视觉上是无法察觉的。


所以,现在的问题是,你想做出什么样的权衡,或者换一种说法"你有多偏执?">你决定从你的图像中剥离的信息越多,你就越有可能无意中丢失一些以后需要的信息。如果去掉EXIF数据,您将不再知道图像是何时拍摄的、在哪里拍摄的或由谁拍摄的。如果去掉ICC颜色配置文件,您的图像可能会在某些查看器中显示为褪色、过饱和或绿色。如果你删除了IPTC信息,如果合同要求你保留它,你可能会侵犯许可证。如果你删除地理参考信息,你的数据可能会变得毫无用处。如果去掉注释,可能会丢失屏蔽信息、版权或标记信息。如果将格式从PNG/TIFF/GIF更改为JPEG,则会失去透明度和准确性。如果从TIFF更改为PNG,将失去存储32位、64位或浮点数据以及4个以上通道的能力。如果您从JPEG更改为PNG,您可能会无意中使文件大几十倍或数百倍。

因此,你可以采取的最偏执的行动是将位图加载到内存中,以无法存储任何其他像素数据(例如PPM或原始RGB(a)字节)的格式保存(出于性能原因,最好保存在内存中,而不是磁盘中),然后将其重新保存为JPEG或PNG。这将丢弃所有EXIF/IPTC/Geo-数据和注释,以及图像结尾或中间附加的任何无关数据。如果您想要一个具体的例子,您可以在终端中使用以下ImageMagick命令:

magick input.jpg -strip ppm:- | magick ppm:- result.jpg

如果你使用PIL/Pillow和Python,你可以做:

from PIL import Image
import numpy as np
# Load image
im = Image.open('image.jpg')                                     
# Convert to format that cannot store IPTC/EXIF or comments, i.e. Numpy array
na = np.array(im)                                                                       
# Create new image from the Numpy array and save
result = Image.fromarray(na).save('clean.jpg')

如果你的图像是PNG格式的,那么你就增加了复杂性——它可能是一个调色板图像,它可能有alpha/透明度信息,你可能会想保留它。看起来可能是这样的:

from PIL import Image
import numpy as np
# Load image
im = Image.open('image.png')                                     
# Convert to format that cannot store IPTC/EXIF or comments, i.e. Numpy array
na = np.array(im)                                                                       
# Create new image from the Numpy array
result = Image.fromarray(na)
# Copy forward the palette, if any
palette = im.getpalette()
if palette != None:
result.putpalette(palette)
# Save result
result.save('clean.png')

如果您需要保留一些元数据,则需要考虑其他选项。

"恶意"内容包含在图像元数据中。

当你读取矩阵中的图像数据(像素、颜色)时(例如,使用python中的pillow aka PIL库),你只会得到图像数据。

当您将其保存回时,元数据将丢失,只保留图像数据。

不过,保存回来可能会产生不希望有的副作用:

  • 有损压缩会改变图像
  • 根据输出格式的不同,透明度可能不受支持,并且会丢失

最新更新