开发者

JAVA如何判断上传文件后缀名是否符合规范MultipartFile

目录
  • Java判断上传文件后缀名是否符合规范MultipartFile
  • java实现对上传文件做安全性检查
    • 1.文件后缀校验
    • 2.校验文件头
      • 1.使用枚举类去校验
      • 2.FileMagic校验文件头
  • 3.校验文件大小
    • 4.示例

      JAVA判断上传文件后缀名是否符合规范MultipartFile

      这里就只做了图片判断,其他判断均一样的逻辑

      文件后缀名枚举

          //文件类型
          public static String IMG_TYPE_PNG = "PNG";
          public static String IMG_TYPE_JPG = "JPG";
          public static String IMG_TYPE_JPEG = "JPEG";
          public static String IMG_TYPE_DMG = "BMP";
          public static String IMG_TYPE_GIF = "GIF";
          public static String IMG_TYPE_SVG = "SVG";

      controller

       @PostMapping("/uploadFlatMap")
          public Result<String> uploadFlatMap(
                @RequestPart(value = "file",required = true) MultipartFile file){
              if(StringUtils.isEmpty(file.getName())){
                  return sendFailedMsg(EnumUtil.BUS_ENUM.FILE_NOTFONUD_ERROR.KEY,file.getOriginalFilename());
              }
              log.info("正在做上传操作,上传文件为:{}",file.getOriginalFilename());
              String suffix = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf(".") + 1);
              if(!(Consts.IMG_TYPE_DMG.equals(suffix.toUpperCase()) ||
                      Cjavascriptonsts.IMG_TYPE_GIF.equals(suffix.toUpperCase()) ||
                      Consts.IMG_TYPE_JPEG.equals(suffix.toUpperCase()) ||
                      Consts.IMG_TYPE_JPG.equals(suffix.toUpperCase()) ||
                      Consts.IMG_TYPE_PNG.equals(suffix.toUpperCase()) ||
                      Consts.IMG_TYPE_SVG.equals(suffix.toUpperCase()))){
                  return sendFailedMsg(EnumUtil.BUS_ENUM.FILE_TYPE_ERROR.KEY,file.getOriginalFilename());
              }

      java实现对上传文件做安全性检查

      对外接口支持文件上传功能时,为避免有人恶意上传有毒或者篡改程序的脚本,需要对上传的文件添加安全性校验。

      1.文件后缀校验

      文件首先校验直观文件上传格式,校验文件后缀是否符合业务要求。以MultipartFile类为例

              String fileName = file.getOriginalFilename();
              if (Strings.isEmpty(fileName)) {
                  throw new RuntimeException("文件名未找到");
              }
              String suffix = fileName.substring(fileName.lastIndexOf(".") + 1);
              if (!Objects.equal(suffix, "xls") && !Objects.equal(suffix, "xlsx")) {
                  throw new RuntimeException("文件类型不正确,需要为xls或者xlsx");
              }

      2.校验文件头

      由于文件后缀可能涉及到篡改的情况出现,因此需要校验文件的魔数,也就是文件头。无论这个文件是否修改文件后缀,这个文件的文件头是不会改变的。下面是常用的文件头格式:

      1.使用枚举类去校验

      JPEG (jpg),文件头:FFD8FFE1
      PNG (png),文件头:89504E47
      GIF (gif),文件头:47494638
      TIFF (tif),文件头:49492A00
      Windows Bitmap (bmp),文件头:424D
      CAD (dwg),文件头:41433130
      Adobe Photoshop (psd),文件头:3842javascript5053
      Rich Text Format (rtf),文件头:7B5C727466
      XML (xml),文件头:3C3F786D6C
      html (html),文件头:68746D6C3E
      Email [thorough only] (eml),文件头:44656C69766572792D646174653A
      Outlook Express (dbx),文件头:CFAD12FEC5FD746F
      Outlook (pst),文件头:2142444E
      MS Word/Excel (xls.or.doc),文件头:D0CF11E0
      MS Access (mdb),文件头:5374616E64617264204A
      WordPerfect (wpd),文件头:FF575043
      Postscript (eps.or.ps),文件头:252150532D41646F6265
      Adobe AcroBAT (pdf),文件头:255044462D312E
      Quicken (qdf),文件头:AC9EBD8F
      Windows Password (pwl),文件头:E3828596
      ZIP Archive (zip),文件头:504B0304
      RAR Archive (rar),文件头:52617221
      Wave (wav),文件头:57415645
      AVI (avi),文件头:41564920
      Real Audio (ram),文件头:2E7261FD
      Real Media (rm),文件头:2E524D46
      MPEG (mpg),文件头:000001BA
      MPEG (mpg),文件头:000001B3
      Quicktime (mov),文件头:6D6F6F76
      Windows Media (asf),文件头:3026B2758E66CF11
      MIDI (mid),文件头:4D546864

      使用上面的文件头去校验的代码示例(这段代码参考:Java 实战系列·Magic 魔数获取文件类型):

      1.魔数枚举类
      public enum FileType {
          /**
           * JPEG
           */
          JPEG("JPEG", "FFD8FF"),
          /**
           * PNG
           */
          PNG("PNG", "89504E47"),
          /**
           * GIF
           */
          GIF("GIF", "47494638"),
          /**
           * TIFF
           */
          TIFF("TIFF", "49492A00"),
          /**
           * Windows bitmap
           */
          BMP("BMP", "424D"),
          /**
           * CAD
           */
          DWG("DWG", "41433130"),
          /**
           * Adobe photoshop
           */
          PSD("PSD", "38425053"),
          /**
           * Rich Text Format
           */
          RTF("RTF", "7B5C727466"),
          /**
           * XML
           */
          XML("XML", "3C3F786D6C"),
          /**
           * HTML
           */
          HTML("HTML", "68746D6C3E"),
          /**
           * Outlook Express
           */
          DBX("DBX", "CFAD12FEC5FD746F "),
          /**
           * Outlook
           */
          PST("PST", "2142444E"),
          /**
           * doc;xls;dot;ppt;xla;ppa;pps;pot;msi;sdw;db
           */
          OLE2("OLE2", "0xD0CF11E0A1B11AE1"),
          /**
           * Microsoft Word/Excel
           */
          XLS_DOC("XLS_DOC", "D0CF11E0"),
          /**
           * Microsoft Access
           */
          MDB("MDB", "5374616E64617264204A"),
          /**
           * Word Perfect
           */
          WPB("WPB", "FF575043"),
          /**
           * Postscript
           */
          EPS_PS("EPS_PS", "252150532D41646F6265"),
          /**
           * Adobe Acrobat
           */
          PDF("PDF", "255044462D312E"),
          /**
           * Windows Password
           */
          PWL("PWL", "E3828596"),
          /**
           * ZIP Archive
           */
          ZIP("ZIP", "504B0304"),
          /**
           * ARAR Archive
           */
          RAR("RAR", "52617221"),
          /**
           * WAVE
           */
          WAV("WAV", "57415645"),
          /**
           * AVI
           */
          AVI("AVI", "41564920"),
          /**
           * Real Audio
           */
          RAM("RAM", "2E7261FD"),
          /**
           * Real Media
           */
          RM("RM", "2E524D46"),
          /**
           * Quicktime
           */
          MOV("MOV", "6D6F6F76"),
          /**
           * Windows Media
           */
          ASF("ASF", "3026B2758E66CF11"),
          /**
           * MIDI
           */
          MID("MID", "4D546864");
          private String key;
          private String value;
          FileType(String key, String value) {
              this.key = key;
              this.value = value;
          }
          public String getValue() {
              return value;
          }
          public String getKey() {
              return key;
          }
      }
      2.获取文件头,并校验是否为Excel
      public class FileUtil {
          /**
           * 获取文件投
           *
           * @param filePath 文件路径
           * @return 16 进制的文php件投信息
           *
           * @throws IOException
           */
          private static String getFileHeader(String filePath) throws IOException {
              byte[] b = new byte[28];
              InputStream inputStream = new FileInputStream(filePath);
              inputStream.read(b, 0, 28);
              inputStream.close();
              return bytes2jshex(b);
          }
          /**
           * 将字节数组转换成16进制字符串
           */
          private static String bytes2hex(byte[] src) {
              StringBuilder stringBuilder = new StringBuilder("");
              if (src == null || src.length <= 0) {
                  return null;
              }
              for (byte b : src) {
                  int v = b & 0xFF;
                  String hv = Integer.toHexString(v);
                  if (hv.length() < 2) {
                      stringBuilder.append(0);
                  }
                  stringBuilder.append(hv);
              }
              return stringBuilder.toString();
          }
          /**
           * 校验是否为excel
           *
           * @param filePath 文件路径
           * @return 文件类型
           *
           * @throws IOException
           */
          public static boolean checkIsExcel(String filePath) throws IOException {
              String fileHead = getFileHeader(filePath);
              if (null == fileHead || fileHead.length() == 0) {
                  return false;
              }
              //校验是否为xls或者xlsx文件
              if (Objects.equal(fileHead, FileType.OLE2.getValue()) || Objects.equal(fileHead, FileType.XLS_DOC.getValue())) {
                  returnQNCakKTpLV true;
              }
              return false;
          }
      }

      除了用上面的魔数头去校验,也可以用poi提供的枚举类FileMagic工具类去校验:

      2.FileMagic校验文件头

      FileMagic魔数值解释:

          OLE2(-2226271756974174256L),   //xls
          OOXML(new int[]{80, 75, 3, 4}), //xlsx, OOXML全称是Office Open XML,OOXML是由微软公司为Office 2007产品开发的技术规范,现已成为国际文档格式标准,兼容前国际标准ODF(Open Document Format)和中国文档标准UOF(Unified Office document Format)。
          XML(new int[]{60, 63, 120, 109, 108}),  //xml
          BIFF2(new int[]{9, 0, 4, 0, 0, 0, 63, 0}), //Excel 2 现在office已经不支持
          BIFF3(new int[]{9, 2, 6, 0, 0, 0, 63, 0}),//Excel 3现在office已经不支持
          BIFF4(new byte[][]{{9, 4, 6, 0, 0, 0, 63, 0}, {9, 4, 6, 0, 0, 0, 0, 1}}),//Excel 4 现在office已经不支持
          MSWRITE(new byte[][]{{49, -66, 0, 0}, {50, -66, 0, 0}}),  //微软原来的写入流,这个不清楚是否还能使用。
          RTF(new String[]{"{\\rtf"}),  //rtf
          PDF(new String[]{"%PDF"}), //pdf
          HTML(new String[]{"<!DOCTYP", "<html", "\n\r<html", "\r\n<html", "\r<html", "\n<html", "<HTML", "\r\n<HTML", "\n\r<HTML", "\r<HTML", "\n<HTML"}),  //HTML
          WORD2(new int[]{219, 165, 45, 0}),//word
          JPEG(new byte[][]{{-1, -40, -1, -37}, {-1, -40, -1, -32, 63, 63, 74, 70, 73, 70, 0, 1}, {-1, -40, -1, -18}, {-1, -40, -1, -31, 63, 63, 69, 120, 105, 102, 0, 0}}),//图片验证,jpeg格式
          GIF(new String[]{"GIF87a", "GIF89a"}),//图片验证,gif格式
          PNG(new int[]{137, 80, 78, 71, 13, 10, 26, 10}),//图片验证,png格式
          TIFF(new String[]{"II*\u0000", "MM\u0000*"}),//图片验证,tiff格式
          WMF(new int[]{215, 205, 198, 154}),//图片验证,wmf格式
          EMF(new int[]{1, 0, 0, 0, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 32, 69, 77, 70}),//图片验证,emf格式
          BMP(new int[]{66, 77}),//图片验证,nmp格式
          UNKNOWN(new byte[][]{new byte[0]});//未知魔数

      使用魔数校验Excel文件代码:

       private static boolean checkIsExcel(InputStream inputStream) throws IOException {
       	//获取文件流的文件头
           FileMagic fileMagic = FileMagic.valueOf(inputStream);
           //判断Excel文件头是否符合xls或者xlsx
           if (Objects.equal(fileMagic, FileMagic.OLE2) || Objects.equal(fileMagic, FileMagic.OOXML)) {
               return true;
           }
           return false;
       }

      3.校验文件大小

      为了避免上传过大文件,影响服务器性能以及带宽。需要对文件大小进行校验,具体文件大小控制以业务为主。

      4.示例

      以校验Excel文件为例:

       /**
           * 校验文件
           *
           * @param file 文件
           * @param fileMaxSize  文件大小限制
           */
          public static void checkExcel(MultipartFile file, Double fileMaxSize) {
              // 文件类型判断 - 校验文件后缀
              String fileName = file.getOriginalFilename();
              if (Strings.isEmpty(fileName)) {
                  throw new RuntimeException("文件名未找到");
              }
              String suffix = fileName.substring(fileName.lastIndexOf(".") + 1);
              if (!Objects.equal(suffix, "xls") && !Objects.equal(suffix, "xlsx")) {
                  throw new RuntimeException("文件类型不正确,需要为xls或者xlsx");
              }
              // 文件类型判断 - 校验文件头内容
              try (InputStream inputStream = file.getInputStream()) {
                  // 获取到上传文件的文件头信息
                  boolean isExcel = checkIsExcel(inputStream);
                  if (!isExcel) {
                      throw new RuntimeException("文件类型不正确,原文件类型需要为xls");
                  }
              } catch (IOException e) {
                  log.error("Get file input stream failed.", e);
                  throw new RuntimeException("文件上传失败");
              }
              // 文件大小校验 - 单位:MB
              long fileBytes = file.getSize();
              double fileSize = (double) fileBytes / 1048576;
              if (fileSize <= 0) {
                  throw new RuntimeException("文件内容为空");
              }
              if (fileSize > fileMaxSize) {
                  throw new RuntimeException("文件上传内容大小超出限制");
              }
          }
          /**
           * 校验文件头
           *
           * @param inputStream
           * @return
           *
           * @throws IOException
           */
          private static boolean checkIsExcel(InputStream inputStream) throws IOException {
              FileMagic fileMagic = FileMagic.valueOf(inputStream);
              if (Objects.equal(fileMagic, FileMagic.OLE2) || Objects.equal(fileMagic, FileMagic.OOXML)) {
                  return true;
              }
              return false;
          }

      到此这篇关于JAVA判断上传文件后缀名是否符合规范MultipartFile的文章就介绍到这了,更多相关java上传文件后缀名内容请搜索编程客栈(www.devze.com)以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程客栈(www.devze.com)!

      0

      上一篇:

      下一篇:

      精彩评论

      暂无评论...
      验证码 换一张
      取 消

      最新开发

      开发排行榜