通常,在WEB系统中,上传文件时都需要做文件的类型校验,大致有如下几种方法:

1. 通过后缀名,如exe,jpg,bmp,rar,zip等等。

2. 通过读取文件,获取文件的Content-type来判断。

3. 通过读取文件流,根据文件流中特定的一些字节标识来区分不同类型的文件。

4. 若是图片,则通过缩放来判断,可以缩放的为图片,不可以的则不是。

然而,在安全性较高的业务场景中,1,2两种方法的校验会被轻易绕过。

1. 伪造后缀名,如图片的,非常容易修改。

2. 伪造文件的Content-type,这个稍微复杂点,为了直观,截图如下:

3.较安全,但是要读取文件,并有16进制转换等操作,性能稍差,但能满足一定条件下对安全的要求,所以建议使用。

但是文件头的信息也可以伪造,截图如下,对于图片可以采用图片缩放或者获取图片宽高的方法避免伪造头信息漏洞。

被伪装成gif的恶意图片文件

对应的Java代码如下:

  1. package apistudy;
  2. import java.awt.image.BufferedImage;
  3. import java.io.File;
  4. import java.io.FileInputStream;
  5. import java.io.FileNotFoundException;
  6. import java.io.IOException;
  7. import java.io.InputStream;
  8. import java.util.HashMap;
  9. import java.util.Iterator;
  10. import java.util.Map;
  11. import java.util.Map.Entry;
  12. import javax.imageio.ImageIO;
  13. import javax.imageio.ImageReader;
  14. import javax.imageio.stream.ImageInputStream;
  15. public class FileTypeTest
  16. {
  17. public final static Map<String, String> FILE_TYPE_MAP = new HashMap<String, String>();
  18. private FileTypeTest(){}
  19. static{
  20. getAllFileType();  //初始化文件类型信息
  21. }
  22. /**
  23. * Created on 2010-7-1
  24. * <p>Discription:[getAllFileType,常见文件头信息]</p>
  25. * @author:[shixing_11@sina.com]
  26. */
  27. private static void getAllFileType()
  28. {
  29. FILE_TYPE_MAP.put("jpg", "FFD8FF"); //JPEG (jpg)
  30. FILE_TYPE_MAP.put("png", "89504E47");  //PNG (png)
  31. FILE_TYPE_MAP.put("gif", "47494638");  //GIF (gif)
  32. FILE_TYPE_MAP.put("tif", "49492A00");  //TIFF (tif)
  33. FILE_TYPE_MAP.put("bmp", "424D"); //Windows Bitmap (bmp)
  34. FILE_TYPE_MAP.put("dwg", "41433130"); //CAD (dwg)
  35. FILE_TYPE_MAP.put("html", "68746D6C3E");  //HTML (html)
  36. FILE_TYPE_MAP.put("rtf", "7B5C727466");  //Rich Text Format (rtf)
  37. FILE_TYPE_MAP.put("xml", "3C3F786D6C");
  38. FILE_TYPE_MAP.put("zip", "504B0304");
  39. FILE_TYPE_MAP.put("rar", "52617221");
  40. FILE_TYPE_MAP.put("psd", "38425053");  //Photoshop (psd)
  41. FILE_TYPE_MAP.put("eml", "44656C69766572792D646174653A");  //Email [thorough only] (eml)
  42. FILE_TYPE_MAP.put("dbx", "CFAD12FEC5FD746F");  //Outlook Express (dbx)
  43. FILE_TYPE_MAP.put("pst", "2142444E");  //Outlook (pst)
  44. FILE_TYPE_MAP.put("xls", "D0CF11E0");  //MS Word
  45. FILE_TYPE_MAP.put("doc", "D0CF11E0");  //MS Excel 注意:word 和 excel的文件头一样
  46. FILE_TYPE_MAP.put("mdb", "5374616E64617264204A");  //MS Access (mdb)
  47. FILE_TYPE_MAP.put("wpd", "FF575043"); //WordPerfect (wpd)
  48. FILE_TYPE_MAP.put("eps", "252150532D41646F6265");
  49. FILE_TYPE_MAP.put("ps", "252150532D41646F6265");
  50. FILE_TYPE_MAP.put("pdf", "255044462D312E");  //Adobe Acrobat (pdf)
  51. FILE_TYPE_MAP.put("qdf", "AC9EBD8F");  //Quicken (qdf)
  52. FILE_TYPE_MAP.put("pwl", "E3828596");  //Windows Password (pwl)
  53. FILE_TYPE_MAP.put("wav", "57415645");  //Wave (wav)
  54. FILE_TYPE_MAP.put("avi", "41564920");
  55. FILE_TYPE_MAP.put("ram", "2E7261FD");  //Real Audio (ram)
  56. FILE_TYPE_MAP.put("rm", "2E524D46");  //Real Media (rm)
  57. FILE_TYPE_MAP.put("mpg", "000001BA");  //
  58. FILE_TYPE_MAP.put("mov", "6D6F6F76");  //Quicktime (mov)
  59. FILE_TYPE_MAP.put("asf", "3026B2758E66CF11"); //Windows Media (asf)
  60. FILE_TYPE_MAP.put("mid", "4D546864");  //MIDI (mid)
  61. }
  62. public static void main(String[] args) throws Exception
  63. {
  64. File f = new File("c://aaa.gif");
  65. if (f.exists())
  66. {
  67. String filetype1 = getImageFileType(f);
  68. System.out.println(filetype1);
  69. String filetype2 = getFileByFile(f);
  70. System.out.println(filetype2);
  71. }
  72. }
  73. /**
  74. * Created on 2010-7-1
  75. * <p>Discription:[getImageFileType,获取图片文件实际类型,若不是图片则返回null]</p>
  76. * @param File
  77. * @return fileType
  78. * @author:[shixing_11@sina.com]
  79. */
  80. public final static String getImageFileType(File f)
  81. {
  82. if (isImage(f))
  83. {
  84. try
  85. {
  86. ImageInputStream iis = ImageIO.createImageInputStream(f);
  87. Iterator<ImageReader> iter = ImageIO.getImageReaders(iis);
  88. if (!iter.hasNext())
  89. {
  90. return null;
  91. }
  92. ImageReader reader = iter.next();
  93. iis.close();
  94. return reader.getFormatName();
  95. }
  96. catch (IOException e)
  97. {
  98. return null;
  99. }
  100. catch (Exception e)
  101. {
  102. return null;
  103. }
  104. }
  105. return null;
  106. }
  107. /**
  108. * Created on 2010-7-1
  109. * <p>Discription:[getFileByFile,获取文件类型,包括图片,若格式不是已配置的,则返回null]</p>
  110. * @param file
  111. * @return fileType
  112. * @author:[shixing_11@sina.com]
  113. */
  114. public final static String getFileByFile(File file)
  115. {
  116. String filetype = null;
  117. byte[] b = new byte[50];
  118. try
  119. {
  120. InputStream is = new FileInputStream(file);
  121. is.read(b);
  122. filetype = getFileTypeByStream(b);
  123. is.close();
  124. }
  125. catch (FileNotFoundException e)
  126. {
  127. e.printStackTrace();
  128. }
  129. catch (IOException e)
  130. {
  131. e.printStackTrace();
  132. }
  133. return filetype;
  134. }
  135. /**
  136. * Created on 2010-7-1
  137. * <p>Discription:[getFileTypeByStream]</p>
  138. * @param b
  139. * @return fileType
  140. * @author:[shixing_11@sina.com]
  141. */
  142. public final static String getFileTypeByStream(byte[] b)
  143. {
  144. String filetypeHex = String.valueOf(getFileHexString(b));
  145. Iterator<Entry<String, String>> entryiterator = FILE_TYPE_MAP.entrySet().iterator();
  146. while (entryiterator.hasNext()) {
  147. Entry<String,String> entry =  entryiterator.next();
  148. String fileTypeHexValue = entry.getValue();
  149. if (filetypeHex.toUpperCase().startsWith(fileTypeHexValue)) {
  150. return entry.getKey();
  151. }
  152. }
  153. return null;
  154. }
  155. /**
  156. * Created on 2010-7-2
  157. * <p>Discription:[isImage,判断文件是否为图片]</p>
  158. * @param file
  159. * @return true 是 | false 否
  160. * @author:[shixing_11@sina.com]
  161. */
  162. public static final boolean isImage(File file){
  163. boolean flag = false;
  164. try
  165. {
  166. BufferedImage bufreader = ImageIO.read(file);
  167. int width = bufreader.getWidth();
  168. int height = bufreader.getHeight();
  169. if(width==0 || height==0){
  170. flag = false;
  171. }else {
  172. flag = true;
  173. }
  174. }
  175. catch (IOException e)
  176. {
  177. flag = false;
  178. }catch (Exception e) {
  179. flag = false;
  180. }
  181. return flag;
  182. }
  183. /**
  184. * Created on 2010-7-1
  185. * <p>Discription:[getFileHexString]</p>
  186. * @param b
  187. * @return fileTypeHex
  188. * @author:[shixing_11@sina.com]
  189. */
  190. public final static String getFileHexString(byte[] b)
  191. {
  192. StringBuilder stringBuilder = new StringBuilder();
  193. if (b == null || b.length <= 0)
  194. {
  195. return null;
  196. }
  197. for (int i = 0; i < b.length; i++)
  198. {
  199. int v = b[i] & 0xFF;
  200. String hv = Integer.toHexString(v);
  201. if (hv.length() < 2)
  202. {
  203. stringBuilder.append(0);
  204. }
  205. stringBuilder.append(hv);
  206. }
  207. return stringBuilder.toString();
  208. }
  209. }

这样,不管是传入的文件有后缀名,还是无后缀名,或者修改了后缀名,真正获取到的才是该文件的实际类型,这样避免了一些想通过修改后缀名或者Content-type信息来攻击的因素。但是性能与安全永远是无法同时完美的,安全的同时付出了读取文件的代价。本人建议可采用后缀名与读取文件的方式结合校验,毕竟攻击是少数,后缀名的校验能排除大多数用户,在后缀名获取不到时再通过获取文件真实类型校验,这样来适当提高性能。

原文出处:

[1] shixing_11, Java判断文件类型 ,http://blog.csdn.net/shixing_11/article/details/5708145

Java判断文件类型的更多相关文章

  1. 用java流方式判断文件类型

    这个方法只能在有限的范围内有效.并不是万金油 比如 图片类型判断,音频文件格式判断,视频文件格式判断等这种肯定是2进制且专业性很强的文件类型判断. 下面给出完整版代码 首先是文件类型枚取 packag ...

  2. java文件上传,自动判断文件类型

    public enum FileType { /** * JEPG. */ JPEG("FFD8FF"), /** * PNG. */ PNG("89504E47&quo ...

  3. java判断文件真实类型

    代码如下: import java.io.FileInputStream; import java.io.IOException; import java.util.HashMap; /** * &l ...

  4. 使用apache.tika判断文件类型

    一. 判断文件类型一般可采用两种方式 1. 后缀名判断 简单易操作,但无法准确判断类型 2. 文件头信息判断 通常可以判断文件类型,但有些文件类型无法判断(如word和excel头信息的前几个字节是一 ...

  5. Python之基于十六进制判断文件类型

    核心代码: #!/usr/bin/env python # -*- coding: utf-8 -*- # @Author : suk import struct from io import Byt ...

  6. JavaScript根据文件名判断文件类型

    //JavaScript根据文件名判断文件类型 var imgExt = new Array(".png",".jpg",".jpeg",& ...

  7. 利用PHP取二进制文件头判断文件类型

    <?php $files = array('D:\no.jpg', 'D:\no.png','D:\no2.JPEG','D:\no.BMP'); $fileTypes = array( 779 ...

  8. Linux中用st_mode判断文件类型

    Linux中用st_mode判断文件类型 2012-12-11 12:41 14214人阅读 评论(4) 收藏 举报  分类: Linux(8)  C/C++(20)  版权声明:本文为博主原创文章, ...

  9. php 读取文件头判断文件类型的实现代码

    php代码实现读取文件头判断文件类型,支持图片.rar.exe等后缀. 例子: <?php $filename = "11.jpg"; //为图片的路径可以用d:/uploa ...

随机推荐

  1. 『Norma 分治』

    Norma Description Input Format 第1行,一个整数N: 第2~n+1行,每行一个整数表示序列a. Output Format 输出答案对10^9取模后的结果. Sample ...

  2. 前端学习:JS面向对象知识学习(图解)

    前端学习:JS面向对象知识学习(图解) 前端学习:JS(面向对象)代码笔记 JS面向对象图解知识全览 创建类和对象 方式1:使用Object()函数 方式2:使用自变量 方式3:使用工厂函数 创建多个 ...

  3. RAID(独立磁盘冗余阵列)简介

    RAID(独立磁盘冗余阵列) 在大数据技术出现之前,人们就需要面对这些关于存储的问题,对应的解决方案就是RAID技术. RAID(独立磁盘冗余阵列)技术主要是为了改善磁盘的存储容量,读写速度,增强磁盘 ...

  4. Javascript 日历插件

    1. The Coolest Calendar 界面非常漂亮的一款日期选择插件,有详细的使用文档,最新版本 1.5. 点击下载    查看示例 2. DatePicker 这款日期插件支持单选.多选和 ...

  5. eclipse 标记任务

    eclipse 标记任务 eclipse Task Tags: TODO -用来提醒该标识处的代码有待返回继续编写.更新或者添加.该标签通常在注释块的源文件顶部. FIXME -该标签用来提醒你代码中 ...

  6. 【转载】Gradle学习 第七章:Java快速入门

    转载地址:http://ask.android-studio.org/?/article/22 7.1. The Java plugin(Java插件) As we have seen, Gradle ...

  7. MySql定时备份脚本

    最近需要对某服务的数据库数据进行备份,因此参考网上教程完成数据库备份脚本. 因为服务的使用频率较低,因此设置定时任务,在每天的中午以及午夜时分进行备份操作. #!/bin/bash # 设置mysql ...

  8. django-配置404页面

    setting.py文件配置 # SECURITY WARNING: don't run with debug turned on in production! DEBUG = False ALLOW ...

  9. The Preliminary Contest for ICPC Asia Xuzhou 2019 E. XKC's basketball team

    题目链接:https://nanti.jisuanke.com/t/41387 思路:我们需要从后往前维护一个递增的序列. 因为:我们要的是wi + m <= wj,j要取最大,即离i最远的那个 ...

  10. 【jsp】案例:显示商品列表 & 问题:List内添加元素,为什么值都变成一样的了

    代码: 1.Product: package domain; public class Product { /* `pid` varchar(50) NOT NULL, `pname` varchar ...