1. 程式人生 > >Java 通過魔數判斷上傳檔案的型別

Java 通過魔數判斷上傳檔案的型別

前言

檔案上傳功能是很多網站都必須的功能,而判斷檔案型別不僅可以過濾檔案的上傳,同時也能防範使用者上傳惡意的可執行檔案和指令碼,以及將檔案上傳伺服器當作免費的檔案儲存伺服器使用。

而對於上傳檔案來說,不能簡單的通過後綴名來判斷檔案的型別,因為惡意攻擊可以將可執行檔案的字尾名稱改為圖片或者其他格式,誘導使用者執行,因此,判斷上傳檔案的型別需要更安全的方式。

與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();  
    } 

}