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);
    }
}

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

java 附件上传时后台验证上传文件的合法性的更多相关文章

  1. 由于ios由UIWebView换成了WKWebview内核后导致webview请求接口文件上传,后台接收不到文件

    2020年4月起App Store将不再接受使用UIWebView的新App上架.2020年12月起将不再接受使用UIWebView的App更新. 解决后台文件接收不到的问题 function GLA ...

  2. java获取mp3的时长和播放mp3文件

    所需包为jaudiotagger-2.2.6-SNAPSHOT.jar和jl1.0.1.jar. import java.io.BufferedInputStream; import java.io. ...

  3. 上传漏洞-js验证

    关于文件上传漏洞,想必玩web安全的同学们都有接触,之前本站也发布过一篇文章介绍文件上传漏洞的各种绕过方法,但是只是有文档却没有演示代码, 最近给公司一客户培训,就照文档中的绕过写出了相应的代码,方便 ...

  4. 你真的了解字典(Dictionary)吗? C# Memory Cache 踩坑记录 .net 泛型 结构化CSS设计思维 WinForm POST上传与后台接收 高效实用的.NET开源项目 .net 笔试面试总结(3) .net 笔试面试总结(2) 依赖注入 C# RSA 加密 C#与Java AES 加密解密

    你真的了解字典(Dictionary)吗?   从一道亲身经历的面试题说起 半年前,我参加我现在所在公司的面试,面试官给了一道题,说有一个Y形的链表,知道起始节点,找出交叉节点.为了便于描述,我把上面 ...

  5. java 附件上传、下载前后端代码

    前言:业务需要:附件上传,需要同时满足浏览器上传,和APP上传附件,并且浏览器端不可使用form表单提交,因为表单提交无法直接获取返回值,除非刷新页面才可显示上传的附件.所以此处使用ajaxfileu ...

  6. 织梦DEDE网站后台如何上传附件

    如题,织梦DEDE网站后台如何上传附件?今天本人遇到这样的问题,在网站后台里点击一番后,成功上传了一个pdf文件和doc文件,特来分享经验. 工具/原料 织梦dede网站 doc文件 方法/步骤 1 ...

  7. [转]WordPress“添加媒体”文件时只显示上传到当前文章的附件图片

    使用WordPress的朋友应该都清楚,特别是喜欢图文并茂的网站,肯定离不开的就是WordPress文章编辑页面的“添加媒体”按钮,每次点击就能弹出一个插入多媒体的界面,然后页面默认就会列举加载所有最 ...

  8. js formData图片上传(单图上传、多图上传)后台java

    单图上传 <div class="imgUp">     <label>头像单图</label>     <input type=&quo ...

  9. 动态input file多文件上传到后台没反应的解决方法!!!

    其实我也不太清除具体是什么原因,但是后面就可以了!!! 我用的是springMVC 自带的文件上传 1.首先肯定是要有springMVC上传文件的相关配置! 2.前端 这是动态input file上传 ...

随机推荐

  1. noip模拟赛(10.4) 背包(pack)

    [题目描述] 蛤布斯有n种商品,第i种物品的价格为ai,价值为bi.有m个人来向蛤布斯购买商品,每个人每种物品只能购买一个.第j个人有cj的钱,他会不停选择一个能买得起的价格最高的商品买走(如果有多个 ...

  2. luogu1022计算器的改良[noip2000提高组Day1 T1]

    题目背景 NCL是一家专门从事计算器改良与升级的实验室,最近该实验室收到了某公司所委托的一个任务:需要在该公司某型号的计算器上加上解一元一次方程的功能.实验室将这个任务交给了一个刚进入的新手ZL先生. ...

  3. AndroidStudio 混淆打包

    AndroidStudio中的项目可以用compile的形式引入github上的开 源项目,可以引用module,而不一定都要用libs文件夹中添加jar包的形式.在最终realease打包时,混淆的 ...

  4. 类集-collection接口

    类集就是一个动态的对象数组,与一般的对象数组不同,类集的对象类容可以随意扩充. 1,对象数组使用的时候会存在一个长度的限制,那么类集是专门解决这种限制的.使用类集可以向数组增加任意多的数据. 2,对象 ...

  5. 基于jquery的tips悬浮消息提示插件tipso

    <a href="javascript:;" class="disabled" data-tipso="Tips" id=" ...

  6. 部署Linux下的man慢查询中文帮助手册环境

    对于Linux运维工作者来说,man查询手册绝对是一个好东西.当我们对一些命令或参数有些许模糊时,可以通过man查询手册来寻求帮助.其实Linux之所以强大, 就在于其强大的命令行, 面对如此繁杂的命 ...

  7. 规范化注释 VVDocumenter的使用方法

    很多时候,为了快速开发,很多的技术文档都是能省则省,这个时候注释就变得异常重要,但是每次都要手动输入规范化的注释,着实也麻烦,但有了VVDocumenter,规范化的注释,主需要输入三个斜线“///” ...

  8. 本地 Maven项目部署到Nexus Repository

    配置Nexus Repository 打开WEB管理界面:http://localhost:8081/nexus/index.html 点击右上角Log In进行登录,默认帐号:admin.密码:ad ...

  9. DEDECMS之二 如何修改模板页

    使用织梦系统最经常是为了仿站,那么模板应该怎么改? 这里主要谈谈关于比较常用的几个模板页 网站主页.列表页.内容页.栏目的调用 1.主页模板 常用组合方法:index.htm + head.htm + ...

  10. PHP中$_SERVER的详细参数与说明

    $_SERVER['PHP_SELF'] #当前正在执行脚本的文件名,与 document root相关. $_SERVER['argv'] #传递给该脚本的参数. $_SERVER['argc'] ...