通常,在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. Web应急:移动端劫持

    PC端访问正常,移动端访问出现异常,比如插入弹窗.嵌入式广告和跳转到第三方网站,将干扰用户的正常使用,对用户体验造成极大伤害. 现象描述 部分网站用户反馈,手机打开网站就会跳转到赌博网站. 问题处理 ...

  2. excel中快捷计算单一列中的所有的值

    excel中快捷计算单一列中的所有的值 比如B列中所有的值 =SUM(B1:B100) 计算B列第一行到第100行的值 又学了一招  如果想统计B列所有的值 可以用 =SUM(B:B)

  3. asp.net web 项目 针对aspx和ashx的 IHttpHandlerFactory 开发

    ASP.NET Framework处理一个Http Request的流程: HttpRequest-->inetinfo.exe-->ASPNET_ISAPI.dll-->ASPNE ...

  4. C# vb .NET读取识别条形码线性条码CODE93

    code93是比较常见的条形码编码规则类型的一种.如何在C#,vb等.NET平台语言里实现快速准确读取该类型条形码呢?答案是使用SharpBarcode! SharpBarcode是C#快速高效.准确 ...

  5. requests方法中content和text区别

    requests对象的get和post方法都会返回一个Response对象,这个对象里面存的是服务器返回的所有信息,包括响应头,响应状态码等.其中返回的网页部分会存在.content和.text两个对 ...

  6. vue项目开发遇见bug

    1.附件的点击问题,与原生交互的问题: 原生的调用对象和vue的调用对象不同,注意原生方法的位置. 2.10.2以下fetch请求数据的问题(检查是否可以使用 can i use) 10.2以下ios ...

  7. HTML实现百度分享插件分享网页

    一.HTML代码如下: <div class="bdsharebuttonbox"> <a href="#" class="bds_ ...

  8. 周黑鸭借力MES,推进智能生产

    1.项目背景介绍 中国食品企业在经过了一些年的行业整体快速增长后,国家对食品行业的管理提出了更加严格的要求,控制更严,准入门槛提高,企业数量成下降趋势. 大中型食品企业已经需要走出国门,走向国际市场, ...

  9. Shell 编程 数组

    本篇主要写一些shell脚本数组的使用. 数组定义 数组名=(value0 value1 vlaue2 ...) 数组名=([0]=value [1]=value [2]=vlaue ...) 列表名 ...

  10. Linux常用指定

    学前理论 linux主要特征 :一切且文件(目录.硬盘等都是文件):硬件都在/dev 目录,如硬盘.U盘为/dev/sd[a-d]: /dev/sr0(/dev/cdrom)是光驱的设备名(df命令查 ...