一般,在文件上傳時,咱們只會根據文件的擴展名來識別並限制所上傳的文件類型。
好比只容許上傳 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是徹底同樣的。
拿了幾個文件來測試,結果以下: