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

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

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

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

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

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

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

2. 伪造文件的Content-type,这个稍微复杂点,

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

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


1. package com.nfschina.utils.file;  
2.   
3. import java.io.File;  
4. import java.io.FileInputStream;  
5. import java.util.HashMap;  
6. import java.util.Iterator;  
7. import java.util.Map;  
8. import java.util.Map.Entry;  
9.   
10. import com.nfschina.utils.BaseException;  
11.   
12. /*********************************************************************** 
13.  * 
14.  * Description: 主要用于判断文件的类型 
15.  * 
16.  ***********************************************************************/  
17.   
18. public class FileTools {  
19.    
20. public final static Map<String, String> FILE_TYPE_MAP = new HashMap<String, String>();              
21.       
22. /*-----------------------------目前可以识别的类型----------------------------*/  
23. private static void getAllFileType()       
24.     {       
25. "jpg", "FFD8FF"); //JPEG        
26. "png", "89504E47"); //PNG        
27. "gif", "47494638"); //GIF       
28. "tif", "49492A00"); //TIFF      
29. "bmp", "424D"); //Windows Bitmap       
30. "dwg", "41433130"); //CAD     
31. "html", "68746D6C3E"); //HTML      
32. "rtf", "7B5C727466"); //Rich Text Format      
33. "xml", "3C3F786D6C");       
34. "zip", "504B0304");       
35. "rar", "52617221");       
36. "psd", "38425053"); //PhotoShop    
37. "eml", "44656C69766572792D646174653A"); //Email [thorough only]     
38. "dbx", "CFAD12FEC5FD746F"); //Outlook Express     
39. "pst", "2142444E"); //Outlook        
40. "office", "D0CF11E0"); //office类型,包括doc、xls和ppt       
41. "mdb", "000100005374616E64617264204A"); //MS Access       
42. "wpd", "FF575043"); //WordPerfect     
43. "eps", "252150532D41646F6265");       
44. "ps", "252150532D41646F6265");       
45. "pdf", "255044462D312E"); //Adobe Acrobat     
46. "qdf", "AC9EBD8F"); //Quicken    
47. "pwl", "E3828596"); //Windows Password   
48. "wav", "57415645"); //Wave     
49. "avi", "41564920");       
50. "ram", "2E7261FD"); //Real Audio       
51. "rm", "2E524D46"); //Real Media       
52. "mpg", "000001BA"); //       
53. "mov", "6D6F6F76"); //Quicktime       
54. "asf", "3026B2758E66CF11"); //Windows Media      
55. "mid", "4D546864"); //MIDI (mid)       
56.     }       
57.    
58. /** 
59.      * 通过读取文件头部获得文件类型 
60.      * @param file 
61.      * @return 文件类型 
62.      * @throws BaseException 
63.      */  
64. public static String getFileType(File file) throws BaseException{  
65.   getAllFileType();  
66. null;  
67.   FileInputStream is;  
68. try {  
69. new FileInputStream(file);  
70. byte[] b = new byte[16];    
71. 0, b.length);    
72.             String filetypeHex = String.valueOf(bytesToHexString(b));    
73.             Iterator<Entry<String, String>> entryiterator = FILE_TYPE_MAP.entrySet().iterator();   
74. while (entryiterator.hasNext()) {   
75.                 Entry<String,String> entry = entryiterator.next();   
76.                 String fileTypeHexValue = entry.getValue();   
77. if (filetypeHex.toUpperCase().startsWith(fileTypeHexValue)) {   
78.                  fileExtendName = entry.getKey();   
79. if(fileExtendName.equals("office")) {  
80.                   fileExtendName = getOfficeFileType(is);  
81.                  }  
82.                  is.close();  
83. break;  
84.                 }  
85.             }  
86.               
87. // 如果不是上述类型,则判断扩展名  
88. if(fileExtendName == null)  
89.             {  
90.              String fileName = file.getName();  
91. // 如果无扩展名,则直接返回空串  
92. if(-1 == fileName.indexOf("."))  
93.              {  
94. return "";  
95.              }  
96. // 如果有扩展名,则返回扩展名  
97. return fileName.substring(fileName.indexOf(".") + 1);  
98.             }  
99.             is.close();  
100. return fileExtendName;  
101. catch (Exception exception) {  
102. throw new BaseException(exception.getMessage(), exception);  
103.   }  
104.  }  
105.    
106. /** 
107.   * 判断office文件的具体类型 
108.   * @param fileInputStream 
109.   * @return office文件具体类型 
110.   * @throws BaseException 
111.   */  
112. private static String getOfficeFileType(FileInputStream fileInputStream) throws BaseException{  
113. "doc";  
114. byte[] b = new byte[512];    
115. try {  
116. 0, b.length);  
117.     String filetypeHex = String.valueOf(bytesToHexString(b));   
118. 992, filetypeHex.length());  
119. if(flagString.toLowerCase().startsWith("eca5c")){  
120. "doc";  
121. else if(flagString.toLowerCase().startsWith("fdffffff09")){  
122. "xls";  
123.           
124. else if(flagString.toLowerCase().startsWith("09081000000")){  
125. "xls";  
126. else {  
127. "ppt";  
128.        }  
129. return officeFileType;  
130. catch (Exception exception) {  
131. throw new BaseException(exception.getMessage(), exception);  
132.    }   
133.   }  
134.     
135. /** 
136.    * 获得文件头部字符串 
137.    * @param src 
138.    * @return 
139.    */  
140. private static String bytesToHexString(byte[] src){       
141. new StringBuilder();       
142. if (src == null || src.length <= 0) {       
143. return null;       
144.         }       
145. for (int i = 0; i < src.length; i++) {       
146. int v = src[i] & 0xFF;    
147.             String hv = Integer.toHexString(v);       
148. if (hv.length() < 2) {       
149. 0);       
150.             }       
151.             stringBuilder.append(hv);       
152.         }       
153. return stringBuilder.toString();       
154.     }    
155.    
156. public static void main(String[] args)  
157.  {  
158.     
159. new File("E:/新闻公告.pdm");  
160.   FileInputStream is;  
161. try{  
162. new FileInputStream(file);  
163. byte[] b = new byte[16];    
164. 0, b.length);    
165. //            String filetypeHex = String.valueOf(bytesToHexString(b));    
166.             String fileName = file.getName();  
167. ".") + 1));  
168. catch(Exception e)  
169.   {  
170.    e.printStackTrace();  
171.   }  
172.     
173.  }