接上篇,Java判断文件类型,继续图片安全问题。若已正确判断出图片类型,防止了绝大多数恶意图片上传。但是若通过修改文件流的方法,给一张本身合法的图片中强行写入一些恶意代码,或者病毒代码,这样前面的方法仍然能够顺利通过,因为它本身是张正确格式的图片,仅仅读取字节与获取图片类型无法做到清除这种类型图片中隐藏的恶意代码。附用UE打开后的恶意图片部分内容,图片的右半部分显示了恶意脚本:
试想,如这种类型图片上传到服务器,当引用了该图片的网页被访问时,而恰好用户的机子装了杀毒软件,则此时杀毒软件会对该页面报警,如果您的网页中存在大量的这种图片,那惨啦,一打开网页,杀毒软件就开始报病毒。这样用户还再敢访问您的网站。
针对这种情况,说白了就是如何清楚合法格式图片中隐藏的恶意信息问题,在工作中无意中发现jmagick可以对图片进行相应处理,而该工具提供的图片缩放方法能将多余的非图片元素清除,那么我们只需要在正确校验格式后对图片按原大小进行一次缩放来清除恶意信息:
代码如下:
package apistudy;
import java.io.IOException;
import magick.ImageInfo;
import magick.MagickImage;
/**
* Created on 2010-7-8
*
Description: [通过jmagick清除图片中的恶意信息]
* @author shixing_11@sina.com
* @version 1.0
*/
public class ImageTypeTest
{
static
{
System.setProperty("jmagick.systemclassloader", "no");
}
/**
* Created on 2010-7-8
*
Discription:[main]
* @param args
* @author:[shixing_11@sina.com]
*/
public static void main(String[] args)
{
String srcFileName = "c:/img/c.jpg";
try
{
filterImageByScale(srcFileName);
}
catch (IOException e)
{
e.printStackTrace();
}
}
/**
* Created on 2010-7-8
*
Discription:[filterImageByScale,清除图片中的恶意代码]
* @param srcFileName
* @throws IOException
* @author:[shixing_11@sina.com]
*/
public final static void filterImageByScale(String srcFileName) throws IOException
{
MagickImage magic = null;
try
{
ImageInfo imgInfo = new ImageInfo(srcFileName);
magic = new MagickImage(imgInfo);
int width = (int) magic.getDimension().getWidth();
int height = (int) magic.getDimension().getHeight();
MagickImage newImage = magic.scaleImage(width, height);
newImage.profileImage("*", null); //清除无用信息
newImage.setImageAttribute("JPEG-Sampling-factors", null); //清除无用信息
newImage.setImageAttribute("comment", null); //清除无用信息
newImage.writeImage(new ImageInfo());
newImage.writeImage(imgInfo);
}
catch (Exception e1)
{
e1.printStackTrace();
}
finally
{
try
{
magic.destroyImages();
}
catch (Exception e2)
{
e2.printStackTrace();
}
}
}
}
运行以上程序后,再打开看原来的图片,恶意内容已经没有了,大小也比以前小了,杀毒软件也不会报病毒了。
附:jmagick工具的使用方法:
1. 从http://downloads.jmagick.org/6.3.9/下载windows下使用的jmagick-win-6.3.9-Q16.zip 。
解压后有两个文件jmagick.jar,jmagick.dll.
将jmagick.dll拷贝到系统目录system32下.
将jmagick.jar放在你的工程lib包下,或者环境变量能找着的地方。
2. 安装ImageMagick,官方网站:http://www.imagemagick.org/
3. 安装ImageMagick-6.3.9-0-Q16-windows-dll.exe
总结: 利用jmagick可以对图片做非常强大的处理,人是仅仅如果是校验图片格式以及用来清除图片中的恶意代码,有点杀鸡用牛九的感 觉,为了一个简单的图片校验便得我们的系统不仅要依赖第三方的包(jmagick.jar,jmagick.dll),而且要依赖 第三方的软件jmagick(因为不安装该软件,该方法所依赖的其它一些dll文件无法找到)。这样使得系统与第三方工具的耦合性太强,增加一个故障点。当然如果JDK本身能提供这种图片中恶意代码的清除功能最好不过了,但感觉有点不现实,因为清楚图片里的恶意代码有点类似杀毒软件的功能,纠结~~~,那位大侠有好的建议告诉下小弟,不甚感激。
注意:使用中容易出现的问题
1.若报如下异常
Exception in thread "imgtest" java.lang.UnsatisfiedLinkError: magick.Magick.init()V
at magick.Magick.init(Native Method)
at magick.Magick.(Magick.java:40)
at com.stress.util.MagickImages.main(MagickImages.java:381)
原因:往往是安装ImageMagick-6.3.9-0-Q16-windows-dll.exe时没有全选安装项造成
解决办法:在安装ImageMagick-6.3.9-0-Q16-windows-dll.exe时要全选安装项,截图如下
2.若报如下异常
java.lang.UnsatisfiedLinkError: no JMagick in java.library.path
java.lang.ClassLoader.loadLibrary(ClassLoader.java:1517)
java.lang.Runtime.loadLibrary0(Runtime.java:788)
java.lang.System.loadLibrary(System.java:834)
magick.Magick.(Magick.java:38)
原因:虽然你的jmagick.jar引入了,但是并没有被默认的类加载器加载进来。
解决办法:在类里加上静态块,用系统的类加载器指定下
static
{
System.setProperty("jmagick.systemclassloader", "no");
}
本程序测试环境: WindowsXP + JDK6.0 +Eclipse3.4.1+ImageMagick-6.3.9-0-Q16-windows
如果要在Linux环境下使用,请使用对应的Linux版本(本人未做测试)。