通常,在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. }