Web 安全漏洞之文件上傳

clipboard.png

文件上傳漏洞及危害

文件上傳漏洞是指網絡攻擊者上傳了一個可執行的文件到服務器上,當開發者沒有對該文件進行合理的校驗及處理的時候,很有可能讓程序執行這個上傳文件導致安全漏洞。大部分網站都會有文件上傳的功能,例如頭像、圖片、視頻等,這塊的邏輯如果處理不當,很容易觸發服務器漏洞。這種漏洞在以文件名爲 URL 特徵的程序中比較多見。嗯,是的說的就是世界上最好的語言 PHP。例如用戶上傳了一個 PHP 文件,拿到對應文件的地址之後就可以執行它了,其中的危害自然不言而喻。那在 Node.js 中就沒有文件上傳漏洞了麼?答案肯定是否的。除了可執行文件外,還有以下幾個潛在的問題。
<!--more-->

文件名

用戶上傳的文件裏有兩個東西經常會被程序使用,一個是文件本身,還有一個就是文件名了。如果文件名被用來讀取或者存儲內容,那麼你就要小心了。攻擊者很有可能會構造一個類似 ../../../attack.jpg 的文件名,如果程序沒有注意直接使用的話很有可能就把服務器的關鍵文件覆蓋導致程序崩潰,甚至更有可能直接將 /etc/passwd 覆蓋寫上攻擊者指定的密碼從而攻破服務器。

有些同學可能會說了,/ 等字符是文件名非法字符,用戶是定義不了這種名字的。你說的沒錯,但是我們要知道我們並不是直接和用戶的文件進行交互的,而是通過 HTTP 請求拿到用戶的文件。在 HTTP 表單上傳請求中,文件名是作爲字符串存儲的。只要是合法的 HTTP 請求格式,攻擊者可以構造請求中的任何內容用於提交給服務器。

POST /upload HTTP/1.1
Host: test.com
Connection: keep-alive
Content-Length: 4237161
Accept: */*
Origin: http://test.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary9pQqgBGwpDfftP8l
Referer: http://test.com
Accept-Encoding: gzip, deflate
Accept-Language: en,zh-CN;q=0.9,zh;q=0.8,zh-TW;q=0.7,da;q=0.6

------WebKitFormBoundary9pQqgBGwpDfftP8l
Content-Disposition: form-data; name="file"; filename="../../attack.jpg"
Content-Type: image/jpeg

------WebKitFormBoundary9pQqgBGwpDfftP8l--

HTML 和 SVG

雖然說 Node.js 在文件上傳服務端可執行程序的漏洞沒有 PHP 那麼高,但是除了服務端可執行之外我們還有客戶端可執行問題,所以還是要做好防備。假設用戶可以上傳任意格式的文件,而如果攻擊者上傳了 HTML 文件後可以配合 CSRF 攻擊進一步製造 XSS 攻擊。

如果你是一個圖片上傳的接口,如果你僅限制 HTML 格式的話也存在問題,因爲圖片中有一種特別的存在是 SVG 格式。SVG 是一種矢量圖形格式,它使用 XML 來描述圖片,在其內部我們是可以插入 <html>, <style>, <script> 等 DOM 標籤的。如果不對 SVG 中的文件內容進行過濾的話,也會發生意想不到的效果。

<svg viewBox="0 0 100 100" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
    <script>alert(111)</script>
    <rect x="25" y="25" width="50" height="50" />
</svg>

軟鏈

我們知道在操作系統中軟鏈本質上也是一種文件,只是這個文件中不包含實際的內容,它包含另外一個文件的路徑名。可以是任意文件或目錄,可以鏈接不同文件系統的文件。如果攻擊者上傳了一個軟鏈文件,軟鏈描述對應的是 /etc/passwd 的話,攻擊者利用程序可以直接讀取到服務器的關鍵文件內容,導致服務器被攻陷。

服務器磁盤

除了文件本身的問題之外,還有一種情況我們需要考慮到的是文件上傳之後的處理。如果我們將用戶上傳的文件存儲到了本地,而沒有限制用戶的上傳頻率的話,就很有可能被攻擊者利用。攻擊者會頻繁的上傳文件導致服務器磁盤佔用 100%,撐爆服務器之後沒辦法處理程序的其它任務進而導致服務器宕機。

防禦方法

針對以上幾個可能出現的漏洞場景,我們需要做到以下幾點:

  1. 對用戶傳入的文件名在使用的時候儘量進行白名單過濾,可以的話儘量不要使用用戶傳入文件名,杜絕從文件名上導致的安全漏洞。
  2. 對文件內容本身做好格式驗證,黑名單或者白名單的方式都可以,不過白名單的方式安全性會更高一點。文件格式不能簡單的判斷文件後綴或者是表單上傳時帶有的 Content-Type 字段,因爲這兩個是用戶上傳內容,都是可被構造的。最好是通過文件頭的魔術數字來讀取,配合白名單列表就能避免這方面的問題。比較著名的使用魔術數字來判斷文件類型的模塊是 https://github.com/sindresorh...,推薦直接使用。
  3. 如果允許用戶上傳 .svg 格式圖片的話,需要針對 SVG 內容進行 HTML 解析,過濾掉 <script>, <foreignObject> 等相關標籤。當然,使用白名單的話是最好不過的了。這裏提供一個比較全的 SVG 合法標籤白名單列表

需要額外提醒的是,如果用戶上傳的壓縮包,程序有解壓的行爲,那麼不僅要按照上述規則校驗壓縮包本身,還需要按照相同的邏輯校驗解壓之後的所有內容。同時針對服務器磁盤被撐爆的情況,推薦限制用戶的上傳頻率降低風險,同時增加磁盤監控告警實時關注線上服務器的狀態。如果存儲到本地不是必須的話也可以使用外部存儲服務來降低服務器這塊的風險。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章