Java 通过魔数判断上传文件的类型 您所在的位置:网站首页 java校验文件类型 Java 通过魔数判断上传文件的类型

Java 通过魔数判断上传文件的类型

2024-01-24 04:12| 来源: 网络整理| 查看: 265

通过魔数值来校验文件类型主要是防止恶意修改等操作。 使用魔数值校验,不管是传入的文件有后缀名,还是无后缀名,或者修改了后缀名,真正获取到的才是该文件的实际类型,这样避免了一些想通过修改后缀名或者Content-type信息来攻击的因素。但是性能与安全永远是无法同时完美的,安全的同时付出了读取文件的代价。本人建议可采用后缀名与读取文件的方式结合校验,毕竟攻击是少数,后缀名的校验能排除大多数用户,在后缀名获取不到时再通过获取文件真实类型校验,这样来适当提高性能。

这里所说的表示不同文件类型的魔术数字,指定是文件的最开头的几个用于唯一区别其它文件类型的字节,有了这些魔术数字,我们就可以很方便的区别不同的文件,这也使得编程变得更加容易,因为我减少了我们用于区别一个文件的文件类型所要花费的时间。

比如,一个JPEG文件,它开头的一些字节可能是类似这样的”ffd8 ffe0 0010 4a46 4946 0001 0101 0047 ……JFIF……G“,这里”ffd8“就表示了这个文件是一个JPEG类型的文件,”ffe0“表示这是JFIF类型结构。

import org.apache.commons.lang3.StringUtils; /** * 文件类型与对应的文件魔数枚举类 * */ public enum FileTypeEnum { /** JPEG (jpg)*/ JPEG("JPG", "FFD8FF"), /** PNG */ PNG("PNG", "89504E47"), /** GIF */ GIF("GIF", "47494638"), /** TIFF (tif) */ TIFF("TIF", "49492A00"), /** Windows bitmap (bmp) */ BMP("BMP","424D"), BMP_16("BMP","424D228C010000000000"), //16色位图(bmp) BMP_24("BMP","424D8240090000000000"), //24位位图(bmp) BMP_256("BMP","424D8E1B030000000000"), //256色位图(bmp) /** CAD (dwg) */ DWG("DWG", "41433130"), /** Adobe photoshop (psd)*/ PSD("PSD", "38425053"), /** Rich Text Format (rtf)*/ RTF("RTF", "7B5C727466"), /** XML */ XML("XML", "3C3F786D6C"), /** HTML (html)*/ HTML("HTML", "68746D6C3E"), /** Email [thorough only] (eml)*/ EML("EML", "44656C69766572792D646174653A"), /** Outlook Express (dbx) */ DBX("DBX", "CFAD12FEC5FD746F "), /** Outlook (pst)*/ PST("", "2142444E"), /** doc;xls;dot;ppt;xla;ppa;pps;pot;msi;sdw;db */ OLE2("OLE2", "0xD0CF11E0A1B11AE1"), /** Microsoft Word/Excel 注意:word 和 excel的文件头一样 */ XLS("XLS", "D0CF11E0"), /** Microsoft Word/Excel 注意:word 和 excel的文件头一样 */ DOC("DOC", "D0CF11E0"), /** Microsoft Word/Excel 2007以上版本文件 注意:word 和 excel的文件头一样 */ DOCX("DOCX", "504B0304"), /** Microsoft Word/Excel 2007以上版本文件 注意:word 和 excel的文件头一样 504B030414000600080000002100*/ XLSX("XLSX", "504B0304"), /** Microsoft Access (mdb)*/ MDB("MDB", "5374616E64617264204A"), /** Word Perfect (wpd)*/ WPB("WPB", "FF575043"), /** Postscript */ EPS("EPS", "252150532D41646F6265"), /** Postscript */ PS("PS", "252150532D41646F6265"), /** Adobe Acrobat (pdf) */ PDF("PDF", "255044462D312E"), /** Quicken (qdf) */ QDF("qdf", "AC9EBD8F"), /** QuickBooks Backup (qdb) */ QDB("qbb", "458600000600"), /** Windows Password (pwl)*/ PWL("PWL", "E3828596"), /** ZIP Archive */ ZIP("", "504B0304"), /** ARAR Archive */ RAR("", "52617221"), /** WAVE (wav) */ WAV("WAV", "57415645"), /** AVI */ AVI("AVI", "41564920"), /** Real Audio (ram)*/ RAM("RAM", "2E7261FD"), /** Real Media (rm) rmvb/rm相同 */ RM("RM", "2E524D46"), /** Real Media (rm) rmvb/rm相同 */ RMVB("RMVB", "2E524D46000000120001"), /** MPEG (mpg) */ MPG("MPG", "000001BA"), /** Quicktime (mov)*/ MOV("MOV", "6D6F6F76"), /** Windows Media (asf) */ ASF("ASF", "3026B2758E66CF11"), /** ARJ Archive */ ARJ("ARJ", "60EA"), /** MIDI (mid) */ MID("MID", "4D546864"), /** MP4 */ MP4("MP4", "00000020667479706D70"), /** MP3 */ MP3("MP3", "49443303000000002176"), /** FLV */ FLV("FLV", "464C5601050000000900"), /** 1F8B0800000000000000 */ GZ("GZ", "1F8B08"), /** CSS */ CSS("CSS", "48544D4C207B0D0A0942"), /** JS */ JS("JS", "696B2E71623D696B2E71"), /** Visio */ VSD("VSD", "d0cf11e0a1b11ae10000"), /** WPS文字wps、表格et、演示dps都是一样的 */ WPS("WPS", "d0cf11e0a1b11ae10000"), /** torrent */ TORRENT("TORRENT", "6431303A637265617465"), /** JSP Archive */ JSP("JSP", "3C2540207061676520"), /** JAVA Archive */ JAVA("JAVA", "7061636B61676520"), /** CLASS Archive */ CLASS("CLASS", "CAFEBABE0000002E00"), /** JAR Archive */ JAR("JAR", "504B03040A000000"), /** MF Archive */ MF("MF", "4D616E69666573742D56"), /** EXE Archive */ EXE("EXE", "4D5A9000030000000400"), /** ELF Executable */ ELF("ELF", "7F454C4601010100"), /** Lotus 123 v1 */ WK1("WK1", "2000604060"), /** Lotus 123 v3 */ WK3("WK3", "00001A0000100400"), /** Lotus 123 v5 */ WK4("WK4", "00001A0002100400"), /** Lotus WordPro v9 */ LWP("LWP", "576F726450726F"), /** Sage(sly.or.srt.or.slt;sly;srt;slt) */ SLY("SLY", "53520100"), /** CHM Archive */ /* CHM("CHM", "49545346030000006000"), INI("INI", "235468697320636F6E66"), SQL("SQL", "494E5345525420494E54"), BAT("BAT", "406563686F206f66660D"), PROPERTIES("", "6C6F67346A2E726F6F74"), MXP("", "04000000010000001300"), */ NOT_EXITS_ENUM("", ""); //文件类型对应的名称 private String fileTypeName; //文件类型对应的魔数 private String magicNumberCode; private FileTypeEnum(String fileTypeName, String magicNumberCode) { this.fileTypeName = fileTypeName; this.magicNumberCode = magicNumberCode; } public String getFileTypeName() { return fileTypeName; } public String getMagicNumberCode() { return magicNumberCode; } /** * 根据文件类型获取文件类型魔数编码 * 默认返回标准件 * @param magicNumberCode - 文件类型魔数编码 * @return */ public static FileTypeEnum getByMagicNumberCode(String magicNumberCode) { if (StringUtils.isNotBlank(magicNumberCode)) { for (FileTypeEnum type : values()) { if (magicNumberCode.toUpperCase().startsWith(type.getMagicNumberCode())) { return type; } } } return FileTypeEnum.NOT_EXITS_ENUM; } /** * 根据文件类型后缀名获取枚举 * * @param fileTypeName - 文件类型后缀名 * @return */ public static FileTypeEnum getByFileTypeName(String fileTypeName) { if (StringUtils.isNotBlank(fileTypeName)) { for (FileTypeEnum type : values()) { if (type.getFileTypeName().equals(fileTypeName)) { return type; } } } return FileTypeEnum.NOT_EXITS_ENUM; } }

或者

import java.awt.image.BufferedImage; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.util.Iterator; import javax.imageio.ImageIO; import javax.imageio.ImageReader; import javax.imageio.stream.ImageInputStream; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * 通过文件魔数来判断文件类型 * 可以最大量避免通过后缀名来判断文件类型的漏洞 * * @author 000125 * */ public class FileTypeUtils { private static final Logger LOGGER = LoggerFactory.getLogger(FileTypeUtils.class); /** * 获取图片文件实际类型,若不是图片则返回null] * @param file * @return fileType */ public final static String getImageFileType(File file) { if (isImage(file)) { try { ImageInputStream iis = ImageIO.createImageInputStream(file); Iterator iter = ImageIO.getImageReaders(iis); if (!iter.hasNext()) { return null; } ImageReader reader = iter.next(); iis.close(); return reader.getFormatName(); } catch (IOException e) { return null; } catch (Exception e) { return null; } } return null; } /** * 获取文件类型,包括图片,若格式不是已配置的,则返回null * @param file * @return fileType */ public final static String getFileByFile(File file) { String filetype = null; byte[] b = new byte[50]; try { InputStream is = new FileInputStream(file); is.read(b); filetype = getFileTypeByStream(b); is.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return filetype; } /** * 通过数据流(二进制数据)判断文件类型 * @param b * @return fileType */ public final static String getFileTypeByStream(byte[] b) { String magicNumberCode = String.valueOf(getFileHexString(b)); if (StringUtils.isBlank(magicNumberCode)) { return FileTypeEnum.getByMagicNumberCode(magicNumberCode.toUpperCase()).getFileTypeName(); } return FileTypeEnum.NOT_EXITS_ENUM.getFileTypeName(); } /** * isImage,判断文件是否为图片 * @param file * @return true 是 | false 否 */ public static final boolean isImage(File file){ boolean flag = false; try { BufferedImage bufreader = ImageIO.read(file); int width = bufreader.getWidth(); int height = bufreader.getHeight(); if(width==0 || height==0){ flag = false; }else { flag = true; } } catch (IOException e) { flag = false; }catch (Exception e) { flag = false; } return flag; } /** * 通过文件路径判断文件类型 * @param path * @return * @throws IOException */ public static FileTypeEnum getFileTypeByPath(String path) { // 获取文件头 String magicNumberCode = null; try { magicNumberCode = getFileHeader(path); } catch (Exception e) { e.printStackTrace(); return FileTypeEnum.NOT_EXITS_ENUM; } if (StringUtils.isBlank(magicNumberCode)) { return FileTypeEnum.getByMagicNumberCode(magicNumberCode.toUpperCase()); } return FileTypeEnum.NOT_EXITS_ENUM; } /** * 通过文件路径获取文件头(即文件魔数) * @param path * @return * @throws IOException */ public static String getFileHeader(String path) throws Exception { byte[] b = new byte[28]; InputStream inputStream = null; try { inputStream = new FileInputStream(path); inputStream.read(b, 0, 28); } finally { if (inputStream != null) { inputStream.close(); } } return getFileHexString(b); } /** * 把文件二进制流转换成十六进制数据 * @param b * @return fileTypeHex */ public final static String getFileHexString(byte[] b) { StringBuilder builder = new StringBuilder(); if (b == null || b.length int v = b[i] & 0xFF; String hv = Integer.toHexString(v); if (hv.length()


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有