判断文件类型,非后缀名的方式

上传文件如果不做好安全控制的话,攻击者很有可能上传一些恶意攻击脚本,然后再执行,达到不可告人的目的。于是我们需要判断文件的类型,通常情况下我们只是判断了文件的后缀名,根据文件的后缀名的白名单和黑名单来过滤。这种方式非常不可靠,因为后缀名完全可以伪造。例如exe的伪造成jpg。
 
      通过文件内容的判断文件的类型是目前最可靠的,因为一般根据文件的开头一些字节的特征就能判断这个文件的类型,而不需要读取整个文件,所以可行性也比较高。下面给出一个例子。
 
1、首先定义文件类型的识别数据FileType.java

  1 public enum FileType {
  2     
  3          /**
  4          * JEPG.
  5          */
  6     JPEG("FFD8FF"),
  7  
  8  
  9         /**
 10          * PNG.
 11          */
 12     PNG("89504E47"),
 13  
 14  
 15         /**
 16          * GIF.
 17          */
 18     GIF("47494638"),
 19  
 20  
 21         /**
 22          * TIFF.
 23          */
 24     TIFF("49492A00"),
 25         /**
 26          * RTF.
 27          */
 28     RTF("7B5C727466"),
 29         /**
 30          * DOC
 31          */
 32     DOC("D0CF11E0"),
 33         /**
 34          * XLS
 35          */
 36     XLS("D0CF11E0"),
 37         /**
 38          * ACCESS
 39          */
 40     MDB("5374616E64617264204A"),
 41  
 42  
 43         /**
 44          * Windows Bitmap.
 45          */
 46     BMP("424D"),
 47  
 48  
 49         /**
 50          * CAD.
 51          */
 52     DWG("41433130"),
 53  
 54  
 55         /**
 56          * Adobe Photoshop.
 57          */
 58     PSD("38425053"),
 59  
 60  
 61         /**
 62          * XML.
 63          */
 64     XML("3C3F786D6C"),
 65  
 66  
 67         /**
 68          * HTML.
 69          */
 70     HTML("68746D6C3E"),
 71  
 72  
 73         /**
 74          * Adobe Acrobat.
 75          */
 76     PDF("255044462D312E"),
 77  
 78  
 79         /**
 80          * ZIP Archive.
 81          */
 82     ZIP("504B0304"),
 83  
 84  
 85         /**
 86          * RAR Archive.
 87          */
 88     RAR("52617221"),
 89  
 90  
 91         /**
 92          * Wave.
 93          */
 94     WAV("57415645"),
 95  
 96  
 97         /**
 98          * AVI.
 99          */
100     AVI("41564920");
101     
102     
103     private String value = "";
104     
105     /**
106      * Constructor.
107      * 
108      * @param type 
109      */
110     private FileType(String value) {
111         this.value = value;
112     }
113  
114     public String getValue() {
115         return value;
116     }
117  
118     public void setValue(String value) {
119         this.value = value;
120     }
121 }
View Code

然后读取文件的前面几个字节转化成十六进制

  1 public enum FileType {
  2     
  3          /**
  4          * JEPG.
  5          */
  6     JPEG("FFD8FF"),
  7  
  8  
  9         /**
 10          * PNG.
 11          */
 12     PNG("89504E47"),
 13  
 14  
 15         /**
 16          * GIF.
 17          */
 18     GIF("47494638"),
 19  
 20  
 21         /**
 22          * TIFF.
 23          */
 24     TIFF("49492A00"),
 25         /**
 26          * RTF.
 27          */
 28     RTF("7B5C727466"),
 29         /**
 30          * DOC
 31          */
 32     DOC("D0CF11E0"),
 33         /**
 34          * XLS
 35          */
 36     XLS("D0CF11E0"),
 37         /**
 38          * ACCESS
 39          */
 40     MDB("5374616E64617264204A"),
 41  
 42  
 43         /**
 44          * Windows Bitmap.
 45          */
 46     BMP("424D"),
 47  
 48  
 49         /**
 50          * CAD.
 51          */
 52     DWG("41433130"),
 53  
 54  
 55         /**
 56          * Adobe Photoshop.
 57          */
 58     PSD("38425053"),
 59  
 60  
 61         /**
 62          * XML.
 63          */
 64     XML("3C3F786D6C"),
 65  
 66  
 67         /**
 68          * HTML.
 69          */
 70     HTML("68746D6C3E"),
 71  
 72  
 73         /**
 74          * Adobe Acrobat.
 75          */
 76     PDF("255044462D312E"),
 77  
 78  
 79         /**
 80          * ZIP Archive.
 81          */
 82     ZIP("504B0304"),
 83  
 84  
 85         /**
 86          * RAR Archive.
 87          */
 88     RAR("52617221"),
 89  
 90  
 91         /**
 92          * Wave.
 93          */
 94     WAV("57415645"),
 95  
 96  
 97         /**
 98          * AVI.
 99          */
100     AVI("41564920");
101     
102     
103     private String value = "";
104     
105     /**
106      * Constructor.
107      * 
108      * @param type 
109      */
110     private FileType(String value) {
111         this.value = value;
112     }
113  
114     public String getValue() {
115         return value;
116     }
117  
118     public void setValue(String value) {
119         this.value = value;
120     }
121 }
View Code
2、通过枚举类,管理不同类型文件的文件头(具体每个文件的文件头内容,可以通过UltraEdit工具打开,查看其16进制内容)
  1 package org.hyena.ats.util;
  2  
  3 /**
  4  * 文件类型
  5  * @author zhihao.du
  6  *
  7  */
  8 public enum FileType {
  9     /** 
 10      * JEPG. 
 11      */  
 12     JPEG("FFD8FF"),  
 13   
 14     /** 
 15      * PNG. 
 16      */  
 17     PNG("89504E47"),  
 18   
 19     /** 
 20      * GIF. 
 21      */  
 22     GIF("47494638"),  
 23   
 24     /** 
 25      * TIFF. 
 26      */  
 27     TIFF("49492A00"),  
 28   
 29     /** 
 30      * Windows Bitmap. 
 31      */  
 32     BMP("424D"),  
 33   
 34     /** 
 35      * CAD. 
 36      */  
 37     DWG("41433130"),  
 38   
 39     /** 
 40      * Adobe Photoshop. 
 41      */  
 42     PSD("38425053"),  
 43   
 44     /** 
 45      * Rich Text Format. 
 46      */  
 47     RTF("7B5C727466"),  
 48   
 49     /** 
 50      * XML. 
 51      */  
 52     XML("3C3F786D6C"),  
 53   
 54     /** 
 55      * HTML. 
 56      */  
 57     HTML("68746D6C3E"),  
 58     /** 
 59      * CSS. 
 60      */  
 61     CSS("48544D4C207B0D0A0942"),  
 62     /** 
 63      * JS. 
 64      */  
 65     JS("696B2E71623D696B2E71"),  
 66     /** 
 67      * Email [thorough only]. 
 68      */  
 69     EML("44656C69766572792D646174653A"),  
 70   
 71     /** 
 72      * Outlook Express. 
 73      */  
 74     DBX("CFAD12FEC5FD746F"),  
 75   
 76     /** 
 77      * Outlook (pst). 
 78      */  
 79     PST("2142444E"),  
 80   
 81     /** 
 82      * MS Word/Excel. 
 83      * XLS_DOC:ppt,doc,xls
 84      * XLSX_DOCX:xlsx
 85      */  
 86     XLS_DOC("D0CF11E0"), XLSX_DOCX("504B030414000600080000002100"),
 87     /** 
 88      * Visio 
 89      */  
 90     VSD("d0cf11e0a1b11ae10000"),  
 91     /** 
 92      * MS Access. 
 93      */  
 94     MDB("5374616E64617264204A"),  
 95     /** 
 96      * WPS文字wps、表格et、演示dps都是一样的 
 97      */  
 98     WPS("d0cf11e0a1b11ae10000"),  
 99     /** 
100      * torrent 
101      */  
102     TORRENT("6431303A637265617465"),  
103     /** 
104      * WordPerfect. 
105      */  
106     WPD("FF575043"),  
107   
108     /** 
109      * Postscript. 
110      */  
111     EPS("252150532D41646F6265"),  
112   
113     /** 
114      * Adobe Acrobat. 
115      */  
116     PDF("255044462D312E"),  
117   
118     /** 
119      * Quicken. 
120      */  
121     QDF("AC9EBD8F"),  
122   
123     /** 
124      * Windows Password. 
125      */  
126     PWL("E3828596"),  
127   
128     /** 
129      * ZIP Archive. 
130      */  
131     ZIP("504B0304"),  
132   
133     /** 
134      * RAR Archive. 
135      */  
136     RAR("52617221"),  
137     /** 
138      * JSP Archive. 
139      */  
140     JSP("3C2540207061676520"),  
141     /** 
142      * JAVA Archive. 
143      */  
144     JAVA("7061636B61676520"),  
145     /** 
146      * CLASS Archive. 
147      */  
148     CLASS("CAFEBABE0000002E00"),  
149     /** 
150      * JAR Archive. 
151      */  
152     JAR("504B03040A000000"),  
153     /** 
154      * MF Archive. 
155      */  
156     MF("4D616E69666573742D56"),  
157     /** 
158      *EXE Archive. 
159      */  
160     EXE("4D5A9000030000000400"),  
161     /** 
162      *CHM Archive. 
163      */  
164     CHM("49545346030000006000"),
165     /** 
166      * Wave. 
167      */  
168     WAV("57415645"),  
169   
170     /** 
171      * AVI. 
172      */  
173     AVI("41564920"),  
174   
175     /** 
176      * Real Audio. 
177      */  
178     RAM("2E7261FD"),  
179   
180     /** 
181      * Real Media. 
182      */  
183     RM("2E524D46"),  
184   
185     /** 
186      * MPEG (mpg). 
187      */  
188     MPG("000001BA"),  
189   
190     /** 
191      * Quicktime. 
192      */  
193     MOV("6D6F6F76"),  
194   
195     /** 
196      * Windows Media. 
197      */  
198     ASF("3026B2758E66CF11"),  
199   
200     /** 
201      * MIDI. 
202      */  
203     MID("4D546864"),  
204     /** 
205      * MP4. 
206      */  
207     MP4("00000020667479706d70"),  
208     /** 
209      * MP3. 
210      */  
211     MP3("49443303000000002176"),
212     /** 
213      * FLV. 
214      */  
215     FLV("464C5601050000000900"), 
216     /**
217      * TXT:txt,docx
218      */
219     TXT("0000000000000000000000000000");
220     
221     private String value = "";  
222   
223     /** 
224      * Constructor. 
225      *  
226      * @param type 
227      */  
228     private FileType(String value) {  
229         this.value = value;  
230     }  
231   
232     public String getValue() {  
233         return value;  
234     }  
235   
236     public void setValue(String value) {  
237         this.value = value;  
238     }  
239   
240 }  
View Code
操作枚举类:
  1 package org.hyena.ats.util;
  2  
  3 import java.io.IOException;  
  4 import java.io.InputStream;  
  5   
  6 /**
  7  * 文件类型操作类
  8  * @author zhihao.du
  9  *
 10  */
 11 public final class FileTypeJudge {  
 12   
 13     /** 
 14      * Constructor 
 15      */  
 16     private FileTypeJudge() {
 17     }
 18   
 19     /** 
 20      * 将文件头转换成16进制字符串 
 21      * @param 原生byte 
 22      * @return 16进制字符串 
 23      */  
 24     private static String bytesToHexString(byte[] src) {  
 25         StringBuilder stringBuilder = new StringBuilder();  
 26         if (src == null || src.length <= 0) {
 27             return null;
 28         }  
 29         for (int i = 0; i < src.length; i++) {  
 30             int v = src[i] & 0xFF;  
 31             String hv = Integer.toHexString(v);  
 32             if (hv.length() < 2) {  
 33                 stringBuilder.append(0);  
 34             }  
 35             stringBuilder.append(hv);  
 36         }  
 37         return stringBuilder.toString();  
 38     }  
 39   
 40     /** 
 41      * 得到文件头 
 42      * @param filePath 文件路径 
 43      * @return 文件头 
 44      * @throws IOException 
 45      */  
 46     private static String getFileContent(InputStream is) throws IOException {  
 47         byte[] b = new byte[28];
 48         InputStream inputStream = null;  
 49         try {  
 50             is.read(b, 0, 28);
 51         } catch (IOException e) {  
 52             e.printStackTrace();  
 53             throw e;  
 54         } finally {  
 55             if (inputStream != null) {  
 56                 try {  
 57                     inputStream.close();  
 58                 } catch (IOException e) {  
 59                     e.printStackTrace();
 60                     throw e;  
 61                 }  
 62             }  
 63         }  
 64         return bytesToHexString(b);
 65     }  
 66   
 67     /** 
 68      * 获取文件类型类
 69      * @param filePath 文件路径 
 70      * @return 文件类型 
 71      */  
 72     public static FileType getType(InputStream is) throws IOException {  
 73         String fileHead = getFileContent(is);
 74         if (fileHead == null || fileHead.length() == 0) {  
 75             return null;  
 76         }  
 77         fileHead = fileHead.toUpperCase();  
 78         FileType[] fileTypes = FileType.values();  
 79         for (FileType type : fileTypes) {  
 80             if (fileHead.startsWith(type.getValue())) {  
 81                 return type;  
 82             }
 83         }  
 84         return null;  
 85     }
 86   
 87     /**
 88      * 获取文件类型
 89      * @param is
 90      * @return
 91      * @throws Exception
 92      */
 93     public static String getFileType(InputStream is) throws Exception{
 94         FileType fileType = getType(is);
 95         if(fileType!=null){
 96             return fileType.getValue();            
 97         }
 98         return null;
 99     }
100 }  
View Code
判断接口
 1 /**
 2      * 判断文件格式
 3      * @param file
 4      * @return
 5      */
 6     public static boolean checkFileFormat(MultipartFile file) {
 7         if (file == null) {
 8             return false;
 9         }
10         try {
11             String type = FileTypeJudge.getFileType(file.getInputStream());
12             if(FileType.TXT.getValue().equals(type)){//TXT,DOCX
13                 return true;
14             }
15             if(FileType.XLS_DOC.getValue().equals(type)){//PPT,DOC,XLS
16                 return true;
17             }
18             if(FileType.XLSX_DOCX.getValue().equals(type)){//XLSX
19                 return true;
20             }
21             if(FileType.PDF.getValue().equals(type)){//PDF
22                 return true;
23             }
24             if(FileType.PNG.getValue().equals(type)){//PNG
25                 return true;
26             }
27             if(FileType.JPEG.getValue().equals(type)){//JPG
28                 return true;
29             }
30         }catch (Exception e) {
31             e.printStackTrace();
32             return false;
33         }
34         return false;
35     }
View Code

 

posted @ 2020-12-17 17:22  土生搞IT  阅读(631)  评论(0编辑  收藏  举报