jQuery文件上传前MIME类型校验:解决修改扩展名后误判及异常上传问题
问题根因
- jQuery File Upload插件重复初始化:仅首次校验通过时才初始化上传组件,一旦初始化完成,组件会持续监听文件选择框的change事件,后续校验不通过时,已绑定的上传逻辑仍会自动执行,和前端校验逻辑完全独立。
- 校验时序错位:FileReader读取文件是异步操作,校验逻辑执行时机晚于上传组件的默认触发时机,往往校验失败提示弹出时,文件已经上传完成。
- 校验规则不匹配:魔数校验仅覆盖png/gif/jpeg/pdf四种类型,但上传组件的acceptFileTypes规则还允许doc、docx、xls等格式,这类文件没有魔数校验,修改后缀即可绕过。
修复方案
- 提前初始化上传组件:页面加载完成后直接初始化jQuery File Upload,关闭自动上传(autoUpload设为false),无需放在change事件中按需初始化。
- 校验逻辑嵌入上传流程:将魔数校验逻辑放到上传组件的add回调中,校验通过后手动调用data.submit()触发上传,校验不通过直接终止流程。
- 补充完整魔数校验规则:将acceptFileTypes中允许的所有文件格式对应的魔数补充到校验逻辑中,避免后缀篡改绕过。
- 避免事件重复绑定:初始化上传组件前先解绑旧的change事件,防止逻辑重复执行。
修正后代码示例
'use strict'; // 页面加载完成后直接初始化上传组件 $(function() { // 先解绑旧事件避免重复触发 $('#myfiles').off('change').fileupload({ downloadTemplateId: 'template-download-gallery', uploadTemplateId: 'template-upload-gallery', paramName: 'files[]', url: 'mydrive-upload.php', dataType: 'json', autoUpload: false, // 关闭自动上传,校验通过再手动触发 maxNumberOfFiles: 10, acceptFileTypes: /(\.|\/)(pdf|doc|docx|xls|ppt|zip|gif|jpe?g|png)$/i, add: function(e, data) { var file = data.files[0]; var fileReader = new FileReader(); fileReader.onloadend = function (e) { var arr = (new Uint8Array(e.target.result)).subarray(0, 4); var header = ''; for (var i = 0; i < arr.length; i++) { header += arr[i].toString(16); } var type = 'unknown'; switch (header) { case '89504e47': type = 'image/png'; break; case '47494638': type = 'image/gif'; break; case 'ffd8ffe0': case 'ffd8ffe1': case 'ffd8ffe2': case 'ffd8ffe3': case 'ffd8ffe8': type = 'image/jpeg'; break; case '25504446': type = 'application/pdf'; break; // 补充其他允许格式的魔数,例如doc、docx、zip等 case '504b0304': // zip、docx、xlsx、pptx都用这个头,可根据需要进一步校验 type = 'archive/office'; break; case 'd0cf11e0': // doc、xls、ppt等旧版office文件头 type = 'old-office'; break; } // 按需求调整允许的type范围 if (type === 'unknown') { alert("File Type Not Allowed"); return false; } else { // 校验通过,触发上传 data.submit(); } }; fileReader.readAsArrayBuffer(file); } }); });
额外注意
前端校验只能做第一层拦截,服务端必须同时做魔数校验和格式校验,避免恶意请求绕过前端直接上传非法文件。
内容的提问来源于stack exchange,提问作者Roger
相关产品推荐
相关产品推荐

