使用JAVA如何对图片进行格式检查以及安全检查处理

博客排名30多好像挺厉害

本文出自冯立彬的博客,原地址:http://www.fenglibin.com/use_java_to_check_images_type_and_security.html

一、通常情况下,验证一个文件是否图片,可以通过以下三种方式:

1)、判断文件的扩展名是否是要求的图片扩展名

这种判断是用得比较多的一种方式,不过这种方式非常的不妥,别人稍微的把一个不是图片的文件的扩展名修改为图片的扩展名,就绕开了你的这种校验,如果这上传的文件是shell、php或者jsp,那你的网站基本上可以说就在别人的手里面了。

不过这种判断方式也不是完全没有用,我们可以把它放在判断图片的最外层,如果一个文件连扩展名都不是我们所要求的图片扩展名,那就根本不用后面的内容格式检查了,从一定程度上说,对减少服务器的压力还是有一定的帮助,否则所有的文件都等上传完后成后再通过服务器去判断,那会在一定程度上浪费器资源的。

2)、根据文件的前面几个字节,即常说的魔术数字进行判断,不同文件类型的开头几个字节,可以查看我的另外一篇专站介绍:表示不同文件类型的魔术数字

但是这种判断方式也是非常不靠谱的,因为他只能够验证文件的前面几个字节,如此时有人把一个可执行的PHP文件的扩展名修改为PNG,然后再在前面补上”89 50″两个字节,就又绕开了这种验证方式。

以下是一段通过JAVA代码获取文件前面两个字节的示例程序: 

[java] view plain copy

  1. import java.io.File;  
  2. import java.io.FileInputStream;  
  3. import java.io.IOException;  
  4. import java.io.InputStream;  
  5. public class ImageTypeCheck {  
  6. public static String bytesToHexString(byte[] src) {  
  7.         StringBuilder stringBuilder = new StringBuilder();  
  8. if (src == null || src.length <= 0) {  
  9. return null;  
  10.         }  
  11. for (int i = 0; i < src.length; i++) {  
  12. int v = src[i] & 0xFF;  
  13.             String hv = Integer.toHexString(v);  
  14. if (hv.length() < 2) {  
  15.                 stringBuilder.append(0);  
  16.             }  
  17.             stringBuilder.append(hv);  
  18.         }  
  19. return stringBuilder.toString();  
  20.     }  
  21. public static void main(String[] args) throws IOException {  
  22.         String imagePath = "c:/favicon.png";  
  23.         File image = new File(imagePath);  
  24.         InputStream is = new FileInputStream(image);  
  25. byte[] bt = new byte[2];  
  26.         is.read(bt);  
  27.         System.out.println(bytesToHexString(bt));  
  28.     }  
  29. }  

不过这种判断方式和判断扩展名一样,也不是完全没有用,至少可以在前期在简单的检查,为进入下一步检查做铺垫。

3)、获取图片的宽高属性 如果能够正常的获取到一张图片的宽高属性,那肯定这是一张图片,因为非图片文件我们是获取不到它的宽高属性的,以下是用于获取根据是否可以获取到图片宽高属性来判断这是否一张图片的JAVA代码:

[java] view plain copy

  1. /**
  2.  * 通过读取文件并获取其width及height的方式,来判断判断当前文件是否图片,这是一种非常简单的方式。
  3.  * 
  4.  * @param imageFile
  5.  * @return
  6.  */
  7. public static boolean isImage(File imageFile) {  
  8. if (!imageFile.exists()) {  
  9. return false;  
  10.     }  
  11.     Image img = null;  
  12. try {  
  13.         img = ImageIO.read(imageFile);  
  14. if (img == null || img.getWidth(null) <= 0 || img.getHeight(null) <= 0) {  
  15. return false;  
  16.         }  
  17. return true;  
  18.     } catch (Exception e) {  
  19. return false;  
  20.     } finally {  
  21.         img = null;  
  22.     }  
  23. }  

二、图片文件的安全检查处理 好了,我们终于判断出一个文件是否图片了,可是如果是在一个可以正常浏览的图片文件中加入一些非法的代码呢:

这就是在一张正常的图片末尾增加的一些iframe代码,我曾经尝试过单独打开这张图片,也将这张图片放于网页上打开,虽然这样都不会被执行,但并不代表插入其它的代码也并不会执行,杀毒软件(如AVAST)对这种修改是会报为病毒的。 那我们要如何预防这种东西,即可以正常打开,又具有正确的图片文件扩展名,还可以获取到它的宽高属性?呵,我们这个时候可以对这个图片进地重写,给它增加水印或者对它进行resize操作,这样新生成的图片就不会再包含这样的恶意代码了,以下是一个增加水印的JAVA实现:

[java] view plain copy

  1. /**
  2.      * 添加图片水印
  3.      * 
  4.      * @param srcImg 目标图片路径,如:C:\\kutuku.jpg
  5.      * @param waterImg 水印图片路径,如:C:\\kutuku.png
  6.      * @param x 水印图片距离目标图片左侧的偏移量,如果x<0, 则在正中间
  7.      * @param y 水印图片距离目标图片上侧的偏移量,如果y<0, 则在正中间
  8.      * @param alpha 透明度(0.0 -- 1.0, 0.0为完全透明,1.0为完全不透明)
  9.      * @throws IOException
  10.      */
  11. public final static void addWaterMark(String srcImg, String waterImg, int x, int y, float alpha) throws IOException {  
  12. // 加载目标图片
  13.         File file = new File(srcImg);  
  14.         String ext = srcImg.substring(srcImg.lastIndexOf(".") + 1);  
  15.         Image image = ImageIO.read(file);  
  16. int width = image.getWidth(null);  
  17. int height = image.getHeight(null);  
  18. // 将目标图片加载到内存。
  19.         BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);  
  20.         Graphics2D g = bufferedImage.createGraphics();  
  21.         g.drawImage(image, 0, 0, width, height, null);  
  22. // 加载水印图片。
  23.         Image waterImage = ImageIO.read(new File(waterImg));  
  24. int width_1 = waterImage.getWidth(null);  
  25. int height_1 = waterImage.getHeight(null);  
  26. // 设置水印图片的透明度。
  27.         g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, alpha));  
  28. // 设置水印图片的位置。
  29. int widthDiff = width - width_1;  
  30. int heightDiff = height - height_1;  
  31. if (x < 0) {  
  32.             x = widthDiff / 2;  
  33.         } else if (x > widthDiff) {  
  34.             x = widthDiff;  
  35.         }  
  36. if (y < 0) {  
  37.             y = heightDiff / 2;  
  38.         } else if (y > heightDiff) {  
  39.             y = heightDiff;  
  40.         }  
  41. // 将水印图片“画”在原有的图片的制定位置。
  42.         g.drawImage(waterImage, x, y, width_1, height_1, null);  
  43. // 关闭画笔。
  44.         g.dispose();  
  45. // 保存目标图片。
  46.         ImageIO.write(bufferedImage, ext, file);  
  47.     }  

通过以上几种方式,应该可以避免绝大部份图片中带恶意代码的安全问题,不过由于我个人的才疏学浅,可能有没有考虑周全的地方,还请各位不吝指教了。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏容器云生态

运维工作常用的shell命令

#seq 1 100    //1到100排序 #seq 1 3 100   //1到100排序,间隔为3 shell中的变量设置规则: 1.变量与变量的内容用...

2226
来自专栏CSDN技术头条

如何在JavaScript中处理大量数据

在几年之前,开发人员不会去考虑在服务端之外处理大量的数据。现在这种观念已经改变了,很多Ajax程序需要在客户端和服务器端传输大量的数据。此外,更新DOM节点的处...

1849
来自专栏企鹅号快讯

UNIX 高手的 10 个习惯

Unix运维工程师看过来:10个能够提高您的 UNIX 命令行效率的好习惯——并在此过程中摆脱不良的使用模式。本文循序渐进地指导您学习几项用于命令行操作的技术,...

1929
来自专栏用户2442861的专栏

百度2014软件开发工程师笔试题详解

1.有一个数据A = [a_1,a_2,a_3.....a_n],n的大小不定,请设计算法将A中的所有数据组合进行输出

3002
来自专栏玄魂工作室

看代码学PHP渗透(3) - 实例化任意对象漏洞

大家好,我们是红日安全-代码审计小组。最近我们小组正在做一个PHP代码审计的项目,供大家学习交流,我们给这个项目起了一个名字叫 PHP-Audit-Labs 。...

6961
来自专栏程序员宝库

正则表达式实例

来源:寒青 链接:https://segmentfault.com/a/1190000012806098 1. 校验基本日期格式 var reg1 = /^\...

38511
来自专栏一个会写诗的程序员的博客

TypeScript 之父简介:TS Anders Hejlsberg: Introducing TypeScript参考资料TypeScript入门指南(JavaScript的超集)

https://channel9.msdn.com/posts/Anders-Hejlsberg-Introducing-TypeScript

1162
来自专栏ChaMd5安全团队

网鼎杯 第四场 部分WriteUp

http://2e8c0fad02d147a6b3f23624556a2fe49a4b7d2b64484f3c.game.ichunqiu.com//.git/

1442
来自专栏orientlu

叙述 C语言编译

工作原因有时候会用python写写测试工具,感受到其快速实现应用的便利,但由于偏底层开发,主力语言依然是C。对于开发语言没有什么优劣概念,在特定的情景下哪种实现...

1881
来自专栏欧阳大哥的轮子

从Xcode10不再支持libstdc++说起

众所周知从Xcode10起,苹果摒弃了对libstdc++库的支持转而支持libc++库了。这两个库在Xcode9甚至更早的版本就已经同时存在于系统中并且可供开...

3583

扫码关注云+社区

领取腾讯云代金券