java 附件上传时后台验证上传文件的合法性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
package  com.huawei.ha.modmgr.util;
import  java.io.FileInputStream;
import  java.io.IOException;
import  java.io.InputStream;
import  java.util.HashMap;
import  java.util.Map;
 
import  org.apache.commons.fileupload.FileItem;
 
 
import  com.huawei.bass.query.core.config.BIPropertiesBean;
/**
  * @Description: 处理上传附件,校验是否合法
  * 在服务器端判断文件类型的问题,故用获取文件头的方式,
  * 直接读取文件的前几个字节,来判断上传文件是否符合格式
  * @author: huangyawei
  * @Created 2013 2013-8-19下午18:58:15
  */
public  class  CheckoutFileType {
     //记录各个文件头信息及对应的文件类型
     public  static  Map<String, String> mFileTypes =  new  HashMap<String, String>();
     
     //所有合法的文件后缀
     public  static  String res_fileType=BIPropertiesBean.getProperty( "fileType" , ".mht.mhtml" );
     
     static  {
         // images          
         mFileTypes.put( "FFD8FFE0" ".jpg" );
         mFileTypes.put( "89504E47" ".png" );
         mFileTypes.put( "47494638" ".gif" );
         mFileTypes.put( "49492A00" ".tif" );
         mFileTypes.put( "424D" ".bmp" );
         
         //PS和CAD
         mFileTypes.put( "38425053" ".psd" );
         mFileTypes.put( "41433130" ".dwg" );  // CAD
         mFileTypes.put( "252150532D41646F6265" , ".ps" );
         
         //办公文档类
         mFileTypes.put( "D0CF11E0" ".doc" );  //ppt、doc、xls
         mFileTypes.put( "504B0304" ".docx" ); //pptx、docx、xlsx   
         
         /**注意由于文本文档录入内容过多,则读取文件头时较为多变-START**/
         mFileTypes.put( "0D0A0D0A" ".txt" ); //txt
         mFileTypes.put( "0D0A2D2D" ".txt" ); //txt
         mFileTypes.put( "0D0AB4B4" ".txt" ); //txt       
         mFileTypes.put( "B4B4BDA8" ".txt" ); //文件头部为汉字
         mFileTypes.put( "73646673" ".txt" ); //txt,文件头部为英文字母
         mFileTypes.put( "32323232" ".txt" ); //txt,文件头部内容为数字
         mFileTypes.put( "0D0A09B4" ".txt" ); //txt,文件头部内容为数字
         mFileTypes.put( "3132330D" ".txt" ); //txt,文件头部内容为数字     
         /**注意由于文本文档录入内容过多,则读取文件头时较为多变-END**/
 
         
         mFileTypes.put( "7B5C727466" ".rtf" );  // 日记本
         
         mFileTypes.put( "255044462D312E" ".pdf" );
         
         //视频或音频类
         mFileTypes.put( "3026B275" , ".wma" );
         mFileTypes.put( "57415645" ".wav" );
         mFileTypes.put( "41564920" ".avi" );
         mFileTypes.put( "4D546864" ".mid" );
         mFileTypes.put( "2E524D46" ".rm" );
         mFileTypes.put( "000001BA" ".mpg" );
         mFileTypes.put( "000001B3" ".mpg" );
         mFileTypes.put( "6D6F6F76" ".mov" );
         mFileTypes.put( "3026B2758E66CF11" ".asf" );
         
         //压缩包
         mFileTypes.put( "52617221" ".rar" );    
         mFileTypes.put( "1F8B08" ".gz" );
         
         //程序文件
         mFileTypes.put( "3C3F786D6C" ".xml" );
         mFileTypes.put( "68746D6C3E" ".html" );
         mFileTypes.put( "7061636B" ".java" );
         mFileTypes.put( "3C254020" ".jsp" );
         mFileTypes.put( "4D5A9000" ".exe" );        
         
         
         mFileTypes.put( "44656C69766572792D646174653A" ".eml" );  // 邮件
         mFileTypes.put( "5374616E64617264204A" ".mdb" ); //Access数据库文件
         
         mFileTypes.put( "46726F6D" ".mht" );
         mFileTypes.put( "4D494D45" ".mhtml" );
         
         
     }
 
     
     
     /**
      * 根据文件的输入流获取文件头信息
      *
      * @param filePath 文件路径
      * @return 文件头信息
      */
     public  static  String getFileType(InputStream  is) {
         byte [] b =  new  byte [ 4 ];
         if (is!= null ){
             try  {
                 is.read(b,  0 , b.length);
             catch  (IOException e) {
                 e.printStackTrace();
             }
         }              
       
        return  mFileTypes.get(getFileHeader(b));
     }
 
     
     /**
      * 根据文件转换成的字节数组获取文件头信息
      *
      * @param filePath
      *            文件路径
      * @return 文件头信息
      */
     public  static  String getFileHeader( byte [] b) {     
         String value = bytesToHexString(b);
         return  value;
     }
 
     /**
      * 将要读取文件头信息的文件的byte数组转换成string类型表示
      * 下面这段代码就是用来对文件类型作验证的方法,
      * 将字节数组的前四位转换成16进制字符串,并且转换的时候,要先和0xFF做一次与运算。
      * 这是因为,整个文件流的字节数组中,有很多是负数,进行了与运算后,可以将前面的符号位都去掉,
      * 这样转换成的16进制字符串最多保留两位,如果是正数又小于10,那么转换后只有一位,
      * 需要在前面补0,这样做的目的是方便比较,取完前四位这个循环就可以终止了
      * @param src要读取文件头信息的文件的byte数组
      * @return 文件头信息
      */
     private  static  String bytesToHexString( byte [] src) {
         StringBuilder builder =  new  StringBuilder();
         if  (src ==  null  || src.length <=  0 ) {
             return  null ;
         }
         String hv;
         for  ( int  i =  0 ; i < src.length; i++) {
             // 以十六进制(基数 16)无符号整数形式返回一个整数参数的字符串表示形式,并转换为大写
             hv = Integer.toHexString(src[i] &  0xFF ).toUpperCase();
             if  (hv.length() <  2 ) {
                 builder.append( 0 );
             }
             builder.append(hv);
         }
         
         System.out.println( "获取文件头信息:" +builder.toString());
         
         return  builder.toString();
     }
 
     
     /**
      * 判断上传的文件是否合法
      * (一)、第一:检查文件的扩展名,
      * (二)、 第二:检查文件的MIME类型 。
      * @param attachDoc
      * @return boolean
      */
     public  static  boolean  getUpFilelegitimacyFlag(FileItem attachDoc){
         boolean  upFlag= false ; //为真表示符合上传条件,为假表标不符合
         if (attachDoc!= null ){           
             String attachName =attachDoc.getName();
             
             System.out.println( "#######上传的文件:" +attachName);
             
             if (! "" .equals(attachName)&&attachName!= null ){
                 
                 /**返回在此字符串中最右边出现的指定子字符串的索引   **/                             
                 String sname = attachName.substring(attachName.lastIndexOf( "." ));
                 
                 /**统一转换为小写**/
                 sname=sname.toLowerCase();
                 
                 /**第一步:检查文件扩展名,是否符合要求范围**/
                 if (res_fileType.indexOf(sname)!=- 1 ){
                     upFlag= true ;
                 }
                 
                 /**
                  * 第二步:获取上传附件的文件头,判断属于哪种类型,并获取其扩展名         
                  * 直接读取文件的前几个字节,来判断上传文件是否符合格式
                  * 防止上传附件变更扩展名绕过校验
                  ***/    
                 if (upFlag){
                     
                     byte [] b =  new  byte [ 4 ];
                     
                     
                     
                     String req_fileType =  null ;
                     try  {
                         req_fileType = getFileType(attachDoc.getInputStream());
                     catch  (IOException e) {
                         // TODO Auto-generated catch block
                         e.printStackTrace();
                     }                  
                     System.out.println( "///用户上传的文件类型///" +req_fileType);
                     /**第三步:检查文件扩展名,是否符合要求范围**/
                     if (req_fileType!= null  && ! "" .equals(req_fileType) && ! "null" .equals(req_fileType)){
                         /**第四步:校验上传的文件扩展名,是否在其规定范围内**/
                         if (res_fileType.indexOf(req_fileType)!=- 1 ){                    
                             upFlag= true ;
                         } else {
                             upFlag= false ;
                         }
                     } else {
                         /**特殊情况校验,如果用户上传的扩展名为,文本文件,则允许上传-START**/
                         if (sname.indexOf( ".txt" )!=- 1 ){
                             upFlag= true ;
                         } else {
                             upFlag= false ;
                         }
                         /**特殊情况校验,如果用户上传的扩展名为,文本文件,则允许上传-END**/
                     }
                 }                                      
             }      
         }
         return  upFlag;
     }
     
     /**
      * 主函数,测试用
      * @param args
      * @throws Exception
      */
     public  static  void  main(String[] args)  throws  Exception {
         //final String fileType = getFileType("D:/BICP-HUAWEI.mht");
         
         FileInputStream is =  null ;
         String value =  null ;
         
         String filePath =  "D:/1.mhtml" ;
         try  {
             is =  new  FileInputStream(filePath);
             byte [] b =  new  byte [ 4 ];
             is.read(b,  0 , b.length);
             value = bytesToHexString(b);
         catch  (Exception e) {
         finally  {
             if  ( null  != is) {
                 try  {
                     is.close();
                 catch  (IOException e) {
                 }
             }
         }
 
         System.out.println(value);
     }
}

用这种方法可以防止用户恶意更改文件后缀伪造合法上传文件的现象。

转载于:https://www.cnblogs.com/bojuetech/p/5938928.html

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值