Java 通過魔數判斷上傳檔案的型別
阿新 • • 發佈:2018-12-09
前言
檔案上傳功能是很多網站都必須的功能,而判斷檔案型別不僅可以過濾檔案的上傳,同時也能防範使用者上傳惡意的可執行檔案和指令碼,以及將檔案上傳伺服器當作免費的檔案儲存伺服器使用。
而對於上傳檔案來說,不能簡單的通過後綴名來判斷檔案的型別,因為惡意攻擊可以將可執行檔案的字尾名稱改為圖片或者其他格式,誘導使用者執行,因此,判斷上傳檔案的型別需要更安全的方式。
與Java的class檔案類似,很多型別的檔案,起始的幾個位元組內容都是固定的,跟據這幾個位元組的內容,就可以判斷檔案的型別,這幾個位元組也被稱為“魔數”,比如class檔案的魔數就是“CAFEBABE”。
通過魔數判斷檔案型別便是一種更安全的方式,其示例原始碼如下。
原始碼
1.新建一個檔案型別的列舉類
public enum FileType { /** JPEG */ JPEG("FFD8FF"), /** PNG */ PNG("89504E47"), /** GIF */ GIF("47494638"), /** TIFF */ TIFF("49492A00"), /** Windows bitmap */ BMP("424D"), /** CAD */ DWG("41433130"), /** Adobe photoshop */ PSD("38425053"), /** Rich Text Format */ RTF("7B5C727466"), /** XML */ XML("3C3F786D6C"), /** HTML */ HTML("68746D6C3E"), /** Outlook Express */ DBX("CFAD12FEC5FD746F "), /** Outlook */ PST("2142444E"), /** doc;xls;dot;ppt;xla;ppa;pps;pot;msi;sdw;db */ OLE2("0xD0CF11E0A1B11AE1"), /** Microsoft Word/Excel */ XLS_DOC("D0CF11E0"), /** Microsoft Access */ MDB("5374616E64617264204A"), /** Word Perfect */ WPB("FF575043"), /** Postscript */ EPS_PS("252150532D41646F6265"), /** Adobe Acrobat */ PDF("255044462D312E"), /** Windows Password */ PWL("E3828596"), /** ZIP Archive */ ZIP("504B0304"), /** ARAR Archive */ RAR("52617221"), /** WAVE */ WAV("57415645"), /** AVI */ AVI("41564920"), /** Real Audio */ RAM("2E7261FD"), /** Real Media */ RM("2E524D46"), /** Quicktime */ MOV("6D6F6F76"), /** Windows Media */ ASF("3026B2758E66CF11"), /** MIDI */ MID("4D546864"); private String value = ""; private FileType(String value) { this.value = value; } public String getValue() { return value; } public void setValue(String value) { this.value = value; } }
2.新建一個檔案工具類,用來判斷上傳檔案的型別
import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; public class FilUtil { /** 判斷檔案型別 */ public static FileType getType(String filePath) throws IOException { // 獲取檔案頭 String fileHead = getFileHeader(filePath); if (fileHead != null && fileHead.length() > 0) { fileHead = fileHead.toUpperCase(); FileType[] fileTypes = FileType.values(); for (FileType type : fileTypes) { if (fileHead.startsWith(type.getValue())) { return type; } } } return null; } /** 讀取檔案頭 */ private static String getFileHeader(String filePath) throws IOException { byte[] b = new byte[28]; InputStream inputStream = null; try { inputStream = new FileInputStream(filePath); inputStream.read(b, 0, 28); } finally { if (inputStream != null) { inputStream.close(); } } return bytesToHex(b); } /** 將位元組陣列轉換成16進位制字串 */ public static String bytesToHex(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(); } }