通常,在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. 【linux】linux修改文件句柄数量,linux文件句柄的修改分为用户级和系统级

    说明: liunx中文件句柄有两种,一种是用户级的,一种是系统级的 文件句柄限制,就是规定的单个进程能够打开的最大文件句柄数量(Socket连接也算在里面,默认大小1024) 1 用户级的修改 1.1 ...

  2. SQL IN 一定走索引吗?

    摘要 IN 一定走索引吗?那当然了,不走索引还能全部扫描吗?好像之前有看到过什么Exist,IN走不走索引的讨论.但是好像看的太久了,又忘记了.哈哈,如果你也忘记了MySQL中IN是如何查询的,就来复 ...

  3. pip 命令安装 rdbtools

    命令 pip install tdbtools 如果出现类似如下错误  Could not fetch URL https://pypi.org/simple/redis/ 说明morning的pip ...

  4. 用友U9 查看功能页面实体

    对着当前页面右键查看属性:   在链接后面加上&__dm=true    在打开的页面将鼠标放到字段上,可以看到页面实体是那一个.

  5. $.ajax()方法

    1.url: 要求为String类型的参数,(默认为当前页地址)发送请求的地址. 2.type: 要求为String类型的参数,请求方式(post或get)默认为get.注意其他http请求方法,例如 ...

  6. Asp.net MVC企业级开发(09)---T4模板

    T4即为Text Template Transformation Toolkit,一种可以由自己去自定义规则的代码生成器.根据业务模型可生成任何形式的文本文件或供程序调用的字符串 在VS中T4模板是没 ...

  7. APS.NET MVC + EF (14)---项目框架搭建

    一:框架搭建     1:先创建Model. 2:创建数据访问接口层.IUserInfoDal 在该接口中定义了常见的方法CURD以及分页方法. public interface IUserInfoD ...

  8. 使用xdebug对php做性能分析调优

    作为PHP程序员我们或多或少都了解或使用过xdebug.此文章记录安装和配置xdebug,以及如何使用它来分析php程序. 我的机器环境: mac, php 安装 xdebug 推荐使用 pecl 安 ...

  9. OCaml (ML家族语言)很好很强大

    理由如下: 1. 强类型,写着放心 2. 函数式. 且不是pure functional, 不用像 Haskell 那样极端.. 3. Algebric Data Types 的模式匹配 实在太爽了 ...

  10. 一文搞定十大经典排序算法(Java实现)

    本文总结十大经典排序算法及变形,并提供Java实现. 参考文章: 十大经典排序算法总结(Java语言实现) 快速排序算法—左右指针法,挖坑法,前后指针法,递归和非递归 快速排序及优化(三路划分等) 一 ...