英文:
Convert image to a fixed format for throwing away all the extra annotations
问题
我正尝试在我的应用程序中实现附件功能,用户可以上传图片文件(png、jpg、jpeg)。我已阅读了OWASP关于图片上传的建议,其中的一个提示是 - 将输入的图像转换为位图(只保留位图数据,丢弃所有额外的注释),然后将位图转换为所需的输出格式。一个合理的方法是转换为PBM格式,然后再转换为PNG格式。
图像以字节数组的形式保存。
我试图使用来自ImageIO库的ImageTranscoder重写上传的图像。但我不太确定它在做什么,以及是否已从图像中删除了所有可能的恶意代码,因为似乎只有元数据正在被重写。
是否有关于如何实现所需目标的建议、最佳实践,以便删除图像文件中的所有可能恶意代码?
英文:
I am trying to implement attachments in my application and user is able to upload image files (png, jpg, jpeg). I have read OWASP recommendations for image uploads, and one of the tips was to - convert the input image to a bitmap (keeping only the bitmap data, and throwing away all the extra annotations), then convert the bitmap to your desired output format. One reasonable way to do this is to convert to PBM format, then convert to PNG.
Image is saved as byte array.
I am trying to rewrite uploaded image by using ImageTranscoder from ImageIO library. But i am not really sure what it is doing, and if all the possibly malicious code is removed from image, because it seems that only metadata is being rewritten.
Is there any suggestions, best practices, of how desired goal should be achieved to remove all possibly malicious code inside image file?
答案1
得分: 0
你不需要像PBM那样的中间文件格式,因为BufferedImage
(这是Java中表示内存中位图的标准方式)只是纯粹的像素数据。你可以从编码的“任何内容”转换为解码的位图,然后再转换为编码的PNG格式。
你可能能够实现你所描述的最简单的方法是:
ImageIO.write(ImageIO.read(input), "PNG", output);
这是相当简单的代码,对于许多现实世界的文件来说可能会出错,或者可能根本不会输出任何内容。你可能希望至少处理最常见的错误情况,类似下面这样:
BufferedImage image = ImageIO.read(input);
if (image == null) {
// TODO: 处理无法读取(解码)图像的情况
}
else if (!ImageIO.write(image, "PNG", output)) {
// TODO: 处理无法写入图像(无法编码为PNG)的情况
}
还有一些需要考虑的事项:上述代码将删除元数据中的恶意代码。然而,可能会有特殊的图像被制作成DoS(小文件解码为巨大的内存表示,TIFF IFD循环等)。这些问题需要在各种输入格式的图像解码器中进行处理。但至少你的输出文件应该是安全的。
此外,恶意代码可以存储在ICC配置文件中,可能会传递到输出图像中。你可以通过强制将所有图像转换为内置的sRGB颜色空间,或者不带ICC配置文件地写入图像来避免这种情况。
附:ImageTranscoder
接口适用于您希望尽可能保留大量元数据的情况(这就是为什么它只有用于元数据的方法),并且允许在不同文件格式之间转换元数据(可以说名称应该是MetadataTranscoder
)。
英文:
You do not need an intermediate file format like PBM, as BufferedImage
(which is the standard way of representing an in-memory bitmap in Java) is just plain pixel data. You can just go from encoded "anything" to decoded bitmap to encoded PNG.
The simplest way you could possibly do what you describe is:
ImageIO.write(ImageIO.read(input), "PNG", output);
This is rather naive code, and will break for many real-world files, or possibly just silently not output anything. You probably want to handle at least the most normal error cases, so something like below:
BufferedImage image = ImageIO.read(input);
if (image == null) {
// TODO: Handle image not read (decoded)
}
else if (!ImageIO.write(image, "PNG", output)) {
// TODO: Handle image not written (could not be encoded as PNG)
}
Other things to consider: The above will remove malicious code in the meta data. However, there might be special images crafted for DoS (small files decoding to huge in-memory representations, TIFF IFD loops, and much more). These problems need to be addressed in the image decoders for the various input formats. But at least your output files should be safe from this.
In addition, malicious code could be stored in the ICC profile, which might be carried over to the output image. You can probably avoid this by force converting all images to the built-in sRGB color space, or writing the images without ICC profiles.
PS: The ImageTranscoder
interface is intended for situations where you want to keep as much meta data as possible (that is why it has methods only for meta data), and allows transformation of meta data from one file format to another (one could argue the name should have been MetadataTranscoder
).
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论