背景:
最近处理(vue2+js)上传文件,后端识别文件中的敏感词的需求,发现如果用户篡改文件后缀,比如把txt文件改为doc,则后端识别不出文件中的敏感词。
原因分析:
前端vue项目+element ui中,el-upload组件中一般是在before-upload钩子函数中控制上传的文件类型,一般通过截取fileName后缀来判断文件类型,针对于篡改后的文件,识别不出源文件类型。
方案思路:
采用读取文件的十六进制文件头来判断文件的真正类型
开发步骤:
1.定义枚举,建立常见的文件类型与文件头魔数对应关系
const FILE_MAGIC_NUM = new Map([
['doc',[0xD0,0xCF,0x11,0xE0]]
])
2.读取文件的二进制流,用二进制视图定型数组的Uint8Array获取文件的魔数,判断该文件魔数是否符合文件的魔数
const checkRealFileType = (file) => {
const jpegHeader = [0xff, 0xd8, 0xff];// jpeg类型的魔数
const reader = new FileReader();
reader.onload = () => {
// 读取文件二进制流
const arrayBuffer = reader.result;
// 用二进制视图定型数组的Uint8Array获取文件的魔数
const uint8Array = new Uint8Array(arrayBuffer);
const magicNum = uint8Array.slice(0, jpegHeader.length);
// 判断该文件魔数是否符合jpeg的魔数
const isJpeg = jpegHeader.every((header, index) => {
return header === uint8Array[index];
});
console.log('源文件', file);
console.log('jpeg的魔数', jpegHeader);
console.log('文件流中的魔数', { magicNum });
console.log('文件真实类型是否为jpeg', isJpeg);
};
reader.readAsArrayBuffer(file);
};
3.在el-upload上传组件before-upload钩子函数中,引用该方法,但因为异步问题,达不到预期效果,所以封装了一个 readBuffer
函数,用于读取文件中指定范围的二进制数据。
function readBuffer(file) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = () => {
resolve(reader.result);
};
reader.onerror = reject;
reader.readAsArrayBuffer(file);
});
}
方案参考链接: