一般,在文件上传时,咱们只会根据文件的扩展名来识别并限制所上传的文件类型。
好比只容许上传 Excel,那么咱们将会查看文件的扩展名是否是.xls
/.xlsx
。html
但咱们知道,在windows系统中,咱们能够任意更改文件的扩展名。 那么若是某些用户,将一个zip的压缩文件,改成 .xls
,在上传时,单单经过扩展名来识别文件,那么它必定是能够经过的。
不少时候,用户都会利用这个漏洞,上传一些看似合法的文件,就如上述场景,将盗版的视频文件改成.pdf
,跳过审查(某些论坛就是这么干的)。前端
需求场景windows
小A: “呀,网盘不能上传视频了,咋办?”后端
大B:”什么状况?”浏览器
小A:”我一上传mp4的文件,它就提示文件名不合法…”服务器
大B:”把扩展名改为pdf试下,下载看的时候,再改过来。”app
…async
小A:”真的能够了诶! 膜拜大神!”测试
那么咱们是否能够经过某些方法,来识别出这类“非法”文件呢?spa
固然不会…
咱们能够作个实验,好比本来就是一个视频文件,咱们改掉扩展名后,再用播放器打开。 测试会发现,播放器同样能够播放该视频。
那么就是说,咱们能够经过读取文件内容,来具体识别出文件类型。
原理在此简单介绍下,其实在每一个文件生成时,都会有个File Signature
(亦称magic number
)。 通常都会在文件头处(即前4 ~ 8位字节)。所以,咱们能够将此段读取出来,与File Signature的库对应,便可找到实际的文件类型。
网上不少的解决方法,都是经过将文件上传到服务器以后,经过后端语言读取识别。
但这样就会产生必定的延迟,若是遇到较大的文件,让用户等待的时间则过长,体验并很差。
在此,着重介绍一下,若是利用HTML5的新特性FileReader
,直接在浏览器中读取文件内容并识别类型。
不废话,上源码
好了,上述核心功能已介绍完成。但使用时,会发现,不过的文件类型,它的Signature的要求是不一样的。
有些是前8位字节,有些则是前4位字节。而有些则不是从文件头开始的,须要从512字节开始读取。
更变态的是,同一扩展名会有多个Signature。
所以,在实际运用时,咱们并不能只截取文件的前几位字节来识别。那如何能够准备识别文件类型呢?
目前思路以下,单独创建一个库,先根据所上传文件的扩展名,找到它所须要截取的文件部分,读取后对应其Signature,若是不匹配,则说明该文件类型与扩展名是不符合的。
目前,我创建的库以下,分别包含每一个文件扩展名对应的Signature,文件截取位置(offset),及截取大小(sizet)。
onLoad(isMatch, signature); // async load callbacks }; reader.readAsArrayBuffer(slice); // Read the slice of the file }
目前经过纯前端读取文件内容来识别文件类型,能够算是最快最简洁的方法。
但一样也存在一些缺陷:
1. 部分文件类型的Signature彻底同样,并不是能彻底区分开
如微软的Office系列文件,.xlsx
,.docx
,.pptx
,其Signature是彻底同样的。
拿了几个文件来测试,结果以下: