You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Vue.js中如何校验上传文件真实格式(防扩展名篡改)

在Vue.js中校验文件真实格式的高效方案

要解决用户篡改扩展名绕过校验的问题,核心是校验文件的Magic Number(文件头二进制标识)——这是文件真实格式的唯一标识,和扩展名无关。下面是一套轻量、低侵入的Vue实现方案:

1. 定义文件类型与Magic Number的映射

先整理常见文件的Magic Number(可根据需求扩展):

const FILE_MAGIC_MAP = {
  png: [0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A],
  jpeg: [0xFF, 0xD8, 0xFF],
  pdf: [0x25, 0x50, 0x44, 0x46] // 对应字符 "%PDF"
};

2. 实现文件真实类型校验函数

在Vue组件中封装异步校验方法,仅读取文件前几个字节(无需加载整个文件,性能拉满):

async validateRealFileType(file, expectedType) {
  const targetMagic = FILE_MAGIC_MAP[expectedType.toLowerCase()];
  if (!targetMagic) return false;

  return new Promise((resolve) => {
    const reader = new FileReader();
    reader.onload = (e) => {
      const fileHeader = new Uint8Array(e.target.result);
      // 逐字节对比Magic Number
      const isMatch = targetMagic.every((byte, idx) => fileHeader[idx] === byte);
      resolve(isMatch);
    };
    // 仅读取文件头部的指定字节数
    reader.readAsArrayBuffer(file.slice(0, targetMagic.length));
  });
}

3. 在上传流程中集成校验

在文件选择的change事件中调用校验,替换原有扩展名校验逻辑:

<template>
  <input 
    type="file" 
    @change="handleFileSelect" 
    accept=".png,.jpeg,.pdf"
  />
</template>

<script>
export default {
  methods: {
    async handleFileSelect(e) {
      const file = e.target.files[0];
      if (!file) return;

      // 提取用户提供的扩展名(仅做辅助,核心看真实格式)
      const fileExt = file.name.split('.').pop().toLowerCase();
      // 校验真实格式
      const isValid = await this.validateRealFileType(file, fileExt);

      if (!isValid) {
        alert(`检测到文件真实格式与扩展名不符,请上传正确格式的文件!`);
        e.target.value = ''; // 清空文件选择
        return;
      }

      // 校验通过,执行后续上传逻辑
      // this.uploadToServer(file);
    },

    async validateRealFileType(file, expectedType) {
      const FILE_MAGIC_MAP = {
        png: [0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A],
        jpeg: [0xFF, 0xD8, 0xFF],
        pdf: [0x25, 0x50, 0x44, 0x46]
      };
      
      const targetMagic = FILE_MAGIC_MAP[expectedType.toLowerCase()];
      if (!targetMagic) return false;

      return new Promise((resolve) => {
        const reader = new FileReader();
        reader.onload = (e) => {
          const fileHeader = new Uint8Array(e.target.result);
          const isMatch = targetMagic.every((byte, idx) => fileHeader[idx] === byte);
          resolve(isMatch);
        };
        reader.readAsArrayBuffer(file.slice(0, targetMagic.length));
      });
    }
  }
};
</script>

关键注意事项

  • 前端校验仅做拦截,后端必须二次校验:前端逻辑可被篡改,后端要复用同样的Magic Number校验逻辑,保证数据安全。
  • 扩展性强:如需支持更多文件类型,只需在FILE_MAGIC_MAP中添加对应Magic Number即可。
  • 性能优异:仅读取文件头部几个字节,大文件也不会有加载延迟。

内容的提问来源于stack exchange,提问作者test user

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 01:40:33