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

}

 

Java中,可以通过以下方法来判断上传文件类型: 1. 通过文件名后缀名判断 可以通过文件名中的后缀名来判断文件类型,例如: ```java String fileName = "example.jpg"; if (fileName.endsWith(".jpg") || fileName.endsWith(".jpeg")) { // 文件类型jpg或jpeg } else if (fileName.endsWith(".png")) { // 文件类型为png } else { // 其他文件类型 } ``` 但需要注意的是,文件名后缀可以被篡改,因此此方法不是十分可靠。 2. 通过文件的MIME类型判断 可以通过文件的MIME类型判断文件类型,例如: ```java import javax.activation.MimetypesFileTypeMap; MimetypesFileTypeMap mimeTypesMap = new MimetypesFileTypeMap(); String mimeType = mimeTypesMap.getContentType(filePath); if (mimeType.startsWith("image/")) { // 文件类型为图片 } else if (mimeType.startsWith("video/")) { // 文件类型为视频 } else if (mimeType.startsWith("text/")) { // 文件类型为文本文件 } else { // 其他文件类型 } ``` 需要注意的是,MIME类型也可以被篡改。 3. 通过文件内容判断 可以通过读取文件的内容来判断文件类型,例如: ```java import java.io.*; public static String getFileType(String filePath) throws IOException { InputStream inputStream = new FileInputStream(filePath); byte[] bytes = new byte[4]; inputStream.read(bytes); inputStream.close(); String type = ""; String fileHead = bytesToHexString(bytes); if (fileHead == null || fileHead.length() == 0) { return null; } fileHead = fileHead.toUpperCase(); FileType[] fileTypes = FileType.values(); for (FileType fileType : fileTypes) { if (fileHead.startsWith(fileType.getValue())) { type = fileType.name(); break; } } return type; } public static String bytesToHexString(byte[] bytes) { StringBuilder stringBuilder = new StringBuilder(); if (bytes == null || bytes.length <= 0) { return null; } for (int i = 0; i < bytes.length; i++) { int v = bytes[i] & 0xFF; String hv = Integer.toHexString(v); if (hv.length() < 2) { stringBuilder.append(0); } stringBuilder.append(hv); } return stringBuilder.toString(); } enum FileType { JPEG("FFD8FF"), // JPEG (jpg) PNG("89504E47"), // PNG (png) GIF("47494638"), // GIF (gif) TIFF("49492A00"), // TIFF (tif) BMP("424D"), // Windows Bitmap (bmp) DWG("41433130"), // CAD (dwg) PSD("38425053"), // Adobe Photoshop (psd) RTF("7B5C727466"), // Rich Text Format (rtf) XML("3C3F786D6C"), // XML (xml) HTML("68746D6C3E"), // HTML (html) PDF("255044462D312E"), // Adobe PDF (pdf) ZIP("504B0304"), // ZIP Archive (zip) RAR("52617221"), // RAR Archive (rar) WAV("57415645"), // Wave (wav) AVI("41564920"), // AVI (avi) MP4("00000020667479706D70"), // MPEG-4 (mp4) MPG("000001BA"), // MPEG (mpg) WMV("3026B2758E66CF11"), // Windows Media Video (wmv) MID("4D546864"); // MIDI (mid) private String value = ""; private FileType(String value) { this.value = value; } public String getValue() { return value; } } ``` 此方法可以通过读取文件的前几个字节来判断文件类型,比较可靠,但需要注意的是,不同类型的文件前几个字节可能是相同的,因此有一定的误判率。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值