java验证各种文件内容合法性工具类及controller调用

package com.zxtech.utils;

import java.io.*;
import java.util.HashMap;
import java.util.Map;


public class FileFormatVerifyUtil {
    private static Map<String,String> FileTypes = new HashMap<>();
    static {
        FileTypes.put("696b2e71623d696b2e71",".js"); // js
        FileTypes.put("252150532D41646F6265",".ps");
        FileTypes.put("1f8b0800000000000000",".gz");// gz文件
        FileTypes.put("4d616e69666573742d56",".mf");// MF文件
        FileTypes.put("ffd8ffe000104a464946",".jpg"); // JPEG (jpg)
        FileTypes.put("ffd8ffe000104a4649460",".jpeg"); // JPEG (jpg)
        FileTypes.put("89504e470d0a1a0a0000",".png"); // PNG (png)
        FileTypes.put("D0CF11E0A1B11AE100000",".ppt"); // PPT (ppt)
        FileTypes.put("504B03041400060008000",".pptx"); // PPTX (pptx)
        FileTypes.put("47494638",".gif"); // GIF (gif)47494638396126026f01
        FileTypes.put("49492a00227105008037",".tif"); // TIFF (tif)
        FileTypes.put("424d",".bmp"); //图(bmp)
        FileTypes.put("41433130313500000000",".dwg"); // CAD (dwg)
        FileTypes.put("3c21646f637479706520",".htm"); // HTM (htm)
        FileTypes.put("48544d4c207b0d0a0942",".css"); // css
        FileTypes.put("7b5c727466315c616e73",".rtf"); // Rich Text Format (rtf)
        FileTypes.put("38425053000100000000",".psd"); // Photoshop (psd)
        FileTypes.put("46726f6d3a203d3f6762",".eml"); // Email [Outlook Express 6] (eml)
        FileTypes.put("d0cf11e0a1b11ae1000000",".doc"); // MS Excel 注意:word、msi 和 excel的文件头一样
        FileTypes.put("d0cf11e0a1b11ae10000000",".xls"); // MS Excel 注意:word、msi 和 excel的文件头一样
        FileTypes.put("d0cf11e0a1b11ae10000",".vsd"); // Visio 绘图
        FileTypes.put("5374616E64617264204A",".mdb"); // MS Access (mdb)
        FileTypes.put("255044462d312e",".pdf");
        FileTypes.put("464c5601050000000900",".flv"); // flv与f4v相同
        FileTypes.put("00000020667479706d70",".mp4");
        FileTypes.put("49443303000000002176",".mp3");
        FileTypes.put("000001ba210001000180",".mpg"); //
        FileTypes.put("3026b2758e66cf11a6d9",".wmv"); // wmv与asf相同
        FileTypes.put("52494646e27807005741",".wav"); // Wave (wav)
        FileTypes.put("52494646d07d60074156",".avi");
        FileTypes.put("4d546864000000060001",".mid"); // MIDI (mid)
        FileTypes.put("504b0304140000000800",".zip");
        FileTypes.put("526172211a0700cf9073",".rar");
        FileTypes.put("235468697320636f6e66",".ini");
        FileTypes.put("504b03040a0000000000",".jar");
        FileTypes.put("4d5a9000030000000400",".exe");// 可执行文件
        FileTypes.put("3c25402070616765206c",".jsp");// jsp文件
        FileTypes.put("3c3f786d6c2076657273",".xml");// xml文件
        FileTypes.put("494e5345525420494e54",".sql");// xml文件
        FileTypes.put("406563686f206f66660d",".bat");// bat文件
        FileTypes.put("49545346030000006000",".chm");// bat文件
        FileTypes.put("04000000010000001300",".mxp");// bat文件
        FileTypes.put("d0cf11e0a1b11ae100000000",".wps");// WPS文字wps、表格et、演示dps都是一样的
        FileTypes.put("3c21444f435459504520",".html"); // HTML (html)
        FileTypes.put("2e524d46000000120001",".rmvb"); // rmvb/rm相同
        FileTypes.put("7061636b616765207765",".java");// java文件
        FileTypes.put("504B030414000600",".docx");// docx文件
        FileTypes.put("504b0304140006000800",".xlsx");// xlsx文件
        FileTypes.put("cafebabe0000002e0041",".class");// bat文件
        FileTypes.put("6431303a637265617465",".torrent");
        FileTypes.put("6c6f67346a2e726f6f74",".properties");// bat文件
        FileTypes.put("CFAD12FEC5FD746F",".dbx"); // Outlook Express (dbx)
        FileTypes.put("6D6F6F76",".mov"); // Quicktime (mov)
        FileTypes.put("FF575043",".wpd"); // WordPerfect (wpd)
        FileTypes.put("2142444E",".pst"); // Outlook (pst)
        FileTypes.put("AC9EBD8F",".qdf"); // Quicken (qdf)
        FileTypes.put("E3828596",".pwl"); // Windows pd (pwl)
        FileTypes.put("2E7261FD",".ram"); // Real Audio (ram)
    }


    /**
     * @Description 根据传入的文件获得后缀,获得指定文件格式byte[]数组中的前N位字符
     *              将传入文件转化为byte[]数组,取前N位.判断传入文件的前N位和我们指定好的文件byte[]的前N位是否相同,
     *              如果相同则文件格式没有被篡改,反之,文件后缀格式被篡改
     * @Param [file]
     * @return boolean 返回true 表示文件格式验证通过, 返回false 文件格式验证失败
     **/
    public static boolean suffixVerify(File file,String fileType){
        //根据文件的后缀获取,获取文件的byte[]的前8位
        if(FileTypes.containsValue(fileType.toLowerCase()) || 1==1){
            for(Map.Entry<String, String> filetype:FileTypes.entrySet()){
                if(filetype.getValue().equals(fileType)){
                    String fileByte8 = String.valueOf(filetype.getKey());
                    //获取传入文件的byte[]的前N位
                    byte[] bytes = inputStream2ByteArray(file);
                    String compareByte = bytesToHexString(bytes);
                    compareByte = compareByte.toUpperCase();
                    //如果传入文件的byte[]的前N位和我们定义好的byte[]的前N位相同,验证通过.
                    if (compareByte.startsWith(fileByte8.toUpperCase())){
                        //如果格式校验成功
                        return true;
                    }
                }
            }
        }else{
            return false;
        }
        return false;
    }

    /**
     * @Description  将file文件转化为byte[]
     * @Param [file]
     * @return byte[]
     **/
    public static   byte[] inputStream2ByteArray(File file){
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        FileInputStream fis = null;
        byte[] buffer = null;
        try {
            fis = new FileInputStream(file);
            //不用读取全部文件,只读文件前面的部分
            byte[] b = new byte[1024];
            fis.read(b);
            bos.write(b, 0, 1024);
            buffer = bos.toByteArray();
        }catch (FileNotFoundException e){
            e.printStackTrace();
        }catch (IOException e1){
            e1.printStackTrace();
        }finally {
            try {
                if(fis !=null){
                    fis.close();
                }
            }catch (Exception e){
                e.printStackTrace();
            }
            try {
                if(bos !=null){
                    bos.close();
                }
            }catch (Exception e){
                e.printStackTrace();
            }
        }
        return buffer;
    }

    /**
     * @Description  取byte[]前N位的为字符串,转成16进制,防止修改字节码
     * @Param [src]
     * @return java.lang.String
     **/
    public static String bytesToHexString(byte[] src) {
        StringBuilder stringBuilder = new StringBuilder();
        if (src == null || src.length <= 0) {
            return null;
        }
        for (int i = 0; i < src.length; i++) {
            int v = src[i] & 0xFF;
            String hv = Integer.toHexString(v);
            if (hv.length() < 2) {
                stringBuilder.append(0);
            }
            stringBuilder.append(hv);
        }
        return stringBuilder.toString();
    }


    /*public static void main(String[] args) throws IOException {
        File f = new File("E:\\工作\\22\\非法文件\\4_1624356044549.jpg");
        System.out.println(FileFormatVerifyUtil.suffixVerify(f,".jpg"));
    }*/
}

Controller类调用  根据业务自行选择一二三步

第一步 先验证文件真实类型
第二步 验证文件后缀名
第三步 验证文件的字节码  防止漏掉手工修改文件名和文件字节码的情况
@ApiOperation("上传文件")
@PostMapping("/uploadFile")
public ResponseEntity<Object> uploadFile(@RequestParam MultipartFile file){
    //配置允许的文件doc,docx,pdf,ppt,xlsx,xls,mp4,jpg,png,jpeg
    Boolean fileType = false;//文件本身的类型是否正确
    //Boolean suffixType = false;
    //判断上传文件的真实类型
    String fileContentType = file.getContentType();
    //文件本身类型配置
    String fileContentTypeStr = "image/jpeg," +
            "image/png," +
            "application/pdf," +
            "video/mp4," +
            "application/msword," +
            "application/vnd.openxmlformats-officedocument.wordprocessingml.document," +
            "application/vnd.openxmlformats-officedocument.presentationml.presentation," +
            "application/vnd.ms-excel," +
            "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet," +
            "application/vnd.ms-powerpoint";
    String fileContentTypeList[] = fileContentTypeStr.split(",");
    for(String fileContentTypeName:fileContentTypeList){
        if(fileContentTypeName.equals(fileContentType)){
            fileType = true;
        }
    }

    //获取文件的后缀名
    //String suffix = FileUtil.getExtensionName(file.getOriginalFilename());
    //根据文件名获取后缀的类型
    String contentName = getFileContentType(file.getOriginalFilename());
    if(!fileType){
        throw new BadRequestException("文件类型不对,请重新选择文件");
    }else if(fileType){
        if(contentName == null ){
            throw new BadRequestException("文件类型不对,请重新选择文件");
        }else if(contentName != null && !contentName.equals(fileContentType)){
            throw new BadRequestException("文件类型不对,请重新选择文件");
        }

    }

    String suffixName = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf("."));
    //将MultipartFile转换为File
    File newFile = FileUtil.toFile(file);
    if(!FileFormatVerifyUtil.suffixVerify(newFile,suffixName)){//suffixVerify返回值true 表示文件格式验证通过, 返回false 文件格式验证失败
        throw new BadRequestException("文件类型不对,请重新选择文件");
    };
    /*//手动配置允许文件后缀名集合
    String fileTypeStr = "doc,docx,pdf,ppt,xlsx,xls,mp4,jpg,png,jpeg";
    String fileTypeNameList[] = fileTypeStr.split(",");
    for(String fileTypeName:fileTypeNameList){
        if(fileTypeName.equals(suffix)){
            suffixType = true;
        }
    }
    if(!fileType || !suffixType){
        throw new BadRequestException("文件类型不对,请重新选择文件");
    }*/
    // 判断文件是否为图片
    /*String suffix = FileUtil.getExtensionName(file.getOriginalFilename());
    if(!FileUtil.IMAGE.equals(FileUtil.getFileType(suffix))){
        throw new BadRequestException("只能上传图片");
    }*/
    //将file转化为MultipartFile,直接使用上面的MultipartFile不好用,上面的MultipartFile被转为file后变为空了  
    MultipartFile newMultipartFile = getMultipartFile(newFile);
    LocalStorage localStorage = localStorageService.create(null, newMultipartFile);
    return new ResponseEntity<>(localStorage, HttpStatus.OK);
}
/**
 * 文件名获取文件的真实类型(MIME)
 * @param fileName
 * @return
 */
private static String getFileContentType(String fileName){
    String returnFileName = fileName.substring(fileName.lastIndexOf("."));
    if(returnFileName != null){
        if(returnFileName.equals(".jpeg") || returnFileName.equals(".jpg")){
            return "image/jpeg";
        }else if(returnFileName.equals(".png")){
            return "image/png";
        }else if(returnFileName.equals(".mp4")){
            return "video/mp4";
        }else if(returnFileName.equals(".ppt")){
            return "application/vnd.ms-powerpoint";
        }else if(returnFileName.equals(".pptx")){
            return "application/vnd.openxmlformats-officedocument.presentationml.presentation";
        }else if(returnFileName.equals(".pdf")){
            return "application/pdf";
        }else if(returnFileName.equals(".doc")){
            return "application/msword";
        }else if(returnFileName.equals(".docx")){
            return "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
        }else if(returnFileName.equals(".xlsx")){
            return "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
        }else if(returnFileName.equals(".xls")){
            return "application/vnd.ms-excel";
        }else{
            return "other";
        }
    }
    return null;
}
/**
 * file转MultipartFile MockMultipartFile需要引入依赖
<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpcore</artifactId>
    <version>4.4.9</version>
</dependency>

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-test</artifactId>
    <version>5.2.9.RELEASE</version>
</dependency>
 * @param file
 * @return
 */
private MultipartFile getMultipartFile(File file){
    FileInputStream fileInputStream = null;
    MultipartFile multipartFile = null;
    try {
        fileInputStream = new FileInputStream(file);
        multipartFile = new MockMultipartFile(file.getName(),file.getName(),
                ContentType.APPLICATION_OCTET_STREAM.toString(),fileInputStream);
    } catch (Exception e) {
        e.printStackTrace();
    }
    return multipartFile;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

态度决定一下

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值