将图像转换为固定格式以丢弃所有额外的注释

Convert image to a fixed format for throwing away all the extra annotations

我正在尝试在我的应用程序中实现附件,并且用户能够上传图像文件(png、jpg、jpeg)。我已经阅读了关于图像上传的 OWASP 建议,其中一个技巧是 - 将输入图像转换为位图(仅保留位图数据,并丢弃所有额外的注释),然后将位图转换为您想要的输出格式。一种合理的方法是先转换为 PBM 格式,然后再转换为 PNG。

图像保存为字节数组。

我正在尝试使用 ImageIO 库中的 ImageTranscoder 重写上传的图像。但是我不太确定它在做什么,以及是否从图像中删除了所有可能的恶意代码,因为似乎只有元数据被重写了。

对于如何达到删除图像文件中所有可能的恶意代码的预期目标,是否有任何建议和最佳实践?

您不需要像 PBM 这样的中间文件格式,因为 BufferedImage(这是在 Java 中表示 in-memory 位图的标准方式)只是普通像素数据。您可以从编码的“任何东西”到解码的位图再到编码的 PNG。

您可以执行您描述的操作的最简单方法是:

ImageIO.write(ImageIO.read(input), "PNG", output);

这是相当幼稚的代码,会破坏许多 real-world 文件,或者可能只是默默地不输出任何内容。您可能希望至少处理最常见的错误情况,因此如下所示:

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)
}

其他需要考虑的事情:以上将删除元数据中的恶意代码。但是,可能存在为 DoS 制作的特殊图像(小文件解码为巨大的 in-memory 表示、TIFF IFD 循环等等)。这些问题需要在各种输入格式的图像解码器中解决。但至少你的 output 文件应该是安全的。

此外,恶意代码可能存储在 ICC 配置文件中,这可能会转移到输出图像中。您可以通过强制将所有图像转换为 built-in sRGB 颜色 space 或在没有 ICC 配置文件的情况下写入图像来避免这种情况。


PS:ImageTranscoder 接口适用于您希望保留 尽可能多的元数据的情况(这就是它具有方法的原因仅用于元数据),并允许将元数据从一种文件格式转换为另一种文件格式(有人可能认为名称应该是 MetadataTranscoder)。