JAVA文件上传防止篡改后缀名

4 篇文章 0 订阅
1 篇文章 0 订阅

记一次小技巧:

我们在做文件上传时会对比文件得后缀名比如.txt,但是假如用户恶意将其他格式得文件通过修改后缀名改为txt上传,则大大影响安全。

所以可通过文件得字节码判断文件得真实类型。

1.定义一下文件头的字节码:

//文件的字节码头
 
public enum FileType {
    /**
     * JEPG.
     */
    JPEG("FFD8FF"),
 
    /**
     * PNG.
     */
    PNG("89504E47"),
 
    /**
     * GIF.
     */
    GIF("47494638"),
 
    /**
     * TIFF.
     */
    TIFF("49492A00"),
 
    TXT("6C657420"),
 
    /**
     * 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).
     */
    PST("2142444E"),
 
    /**
     * MS Word/Excel.
     */
    XLS_DOC("D0CF11E0"),
 
    /**
     * MS Access.
     */
    MDB("5374616E64617264204A"),
 
    /**
     * WordPerfect.
     */
    WPD("FF575043"),
 
    /**
     * Postscript.
     */
    EPS("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).
     */
    MPG("000001BA"),
 
    /**
     * Quicktime.
     */
    MOV("6D6F6F76"),
 
    /**
     * Windows Media.
     */
    ASF("3026B2758E66CF11"),
 
    GZ("1F8B08"),
    /**
     * MIDI.
     */
    MID("4D546864");
   
}

2.获取文件字节码的前N位(因为文件类型的长度不同,所以获取前20位,如果是图片等可以只获得更少位数):


    /**
     * @description 第一步:获取文件输入流
     * @param filePath
     * @throws IOException
     */
    private static String getFileContent(String filePath) throws IOException {
 
        byte[] b = new byte[20];
        InputStream inputStream = null;
        try {
            inputStream = new FileInputStream(filePath);
            /**
             * int read() 从此输入流中读取一个数据字节。int read(byte[] b) 从此输入流中将最多 b.length
             * 个字节的数据读入一个 byte 数组中。 int read(byte[] b, int off, int len)
             *从此输入流中将最多 len 个字节的数据读入一个 byte 数组中。
             * 之所以从输入流中读取20个字节数据,是因为不同格式的文件头魔数长度是不一样的,比如 EML("44656C69766572792D646174653A")和GIF("47494638")
             * 为了提高识别精度所以获取的字节数相应地长一点
             */
            inputStream.read(b, 0, 20);
        } catch (IOException e) {
            e.printStackTrace();
            throw e;
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                    throw e;
                }
            }
        }
        return bytesToHexString(b);
    }
    

3.因为字节码头也是有可能被篡改的,所以将头部转换成16进制

/**
     * @description 第二步:将文件头转换成16进制字符串
     * @param
     * @return 16进制字符串
     */
    private static String bytesToHexString(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);
        }
        System.out.println("文件类型16进制字符串是"+stringBuilder.toString());
        return stringBuilder.toString();
    }
  

4.对比

  /**
     * @description 第三步:根据十六进制字符串判断文件类型格式
     * @param filePath 文件路径
     * @return 文件类型
     */
    public static FileType getType(String filePath) throws IOException {
        String fileHead = getFileContent(filePath);
        if (fileHead == null || fileHead.length() == 0) {
            return null;
        }
        fileHead = fileHead.toUpperCase();
        FileType[] fileTypes = FileType.values();
        for (FileType type : fileTypes) {
//            startsWith() 方法用于检测字符串是否以指定的前缀开始
            if (fileHead.startsWith(type.getValue())) {
                return type;
            }
        }
        return null;
    }
}

  • 0
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
文件上传暴力破解黑名单后缀名是一种攻击方式,攻击者尝试上传被服务器列入黑名单的文件类型。这种攻击的目的是绕过服务器对文件类型的过滤,上传可能存在安全风险的文件。 下面是一些防御措施来防止文件上传暴力破解黑名单后缀名的攻击: 1. 使用白名单而非黑名单:将文件上传过滤机制从黑名单(禁止上传某些文件类型)改为白名单(只允许上传某些受信任的文件类型)。这样可以确保只有预期的文件类型被上传。 2. 对文件进行完整性检查:在接收到上传的文件后,对其进行完整性检查,以确保文件没有被篡改或包含恶意内容。可以通过校验文件的哈希值或进行病毒扫描来验证文件的完整性。 3. 限制文件上传大小:设置合理的上传文件大小限制,防止攻击者通过上传大型文件来耗尽服务器资源或进行其他恶意行为。 4. 验证文件类型:除了通过文件扩展名验证外,还应该通过检查文件的内容类型(MIME类型)来验证文件类型的合法性。这可以防止攻击者通过伪造文件扩展名来绕过检查。 5. 安全审计:定期审计文件上传功能的安全性,检查是否存在漏洞或配置错误。 通过以上防御措施,可以有效减少文件上传暴力破解黑名单后缀名的风险。同时,还应保持对最新的安全威胁和漏洞的了解,并及时更新和修复系统中的安全问题。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值