JAVA如何判断上传文件后缀名是否符合规范MultipartFile
作者:coder阿龙
这篇文章主要介绍了JAVA判断上传文件后缀名是否符合规范MultipartFile,文中通过实例代码介绍了java实现对上传文件做安全性检查,需要的朋友可以参考下
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()) || Consts.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),文件头:38425053 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 进制的文件投信息 * * @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 bytes2hex(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())) { return 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上传文件后缀名内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!