iT邦幫忙

2023 iThome 鐵人賽

DAY 3
0

Input (下篇)

不知不覺來到了 Input (下篇),這次要來介紹 "規範 Input 寫入的範圍":
https://ithelp.ithome.com.tw/upload/images/20230918/20107197w50UJ57krX.png

規範 Input 寫入的範圍

有關規範 Input 寫入的範圍,我們需要確認兩點:

  1. Input 本身真的是表面上看起來的檔案嗎?
  • 確認檔案方式:

    • 驗證檔案格式 & 副檔名
      確保根據允許的文件類型白名單檢查上傳文件的文件副檔名。在服務器端執行此操作,因為可以繞過客戶端檢查。

      • 注意: 此處若只有驗證附檔名肯定是不夠的,若遇到有心人士,還有可能會把文件副檔名改掉,改成其他期望的副檔名,因此,我們仍然需要驗證檔案格式:

      • 如何驗證檔案格式?
        以圖片為例,我們可以使用 File Signature 來確認是否為圖片:
        若要評斷 png,我們就可以判斷該 file 的前幾個 byte 是否與 png 檔的 file signature 前幾個 byte 相符 ?
        https://ithelp.ithome.com.tw/upload/images/20230918/20107197gxXMN36bL0.png

        以 NodeJS 為例,就可以以 Buffer 形式 get 上傳的檔案物件,並把其 Uint8Array 格式的資料取前幾個值來進行比對:

        function isPngOrNot(yourArray) {
        
            if (!yourArray || yourArray.length < 8) {
                return false;
            }
        
            return yourArray[0] === 0x89
                && yourArray[1] === 0x50
                && yourArray[2] === 0x4E
                && yourArray[3] === 0x47
                && yourArray[4] === 0x0D
                && yourArray[5] === 0x0A
                && yourArray[6] === 0x1A
                && yourArray[7] === 0x0A;
        }
        
    • 驗證 Content-type header
      從瀏覽器上傳的文件將附有 Content-Type 標頭。確保提供的類型屬於允許文件類型的白名單。

      以 NodeJS 為例,我們可以以下方式查看:

      app.use('/api/', (req, res, next) => {
          // 使用 req.is 來判斷 content type
          if (req.is('application/json')) {
          // do something
          }
      });
      

      注意: 有經驗的攻擊者有可能會透過寫簡單的 script 來繞過這段檢查
      (https://www.hacksplaining.com/prevention/file-upload)

  • 過濾掉可能是惡意的檔案

    • 更改它的檔案名稱
      避免有心 hacker 可以很直接地用檔名來追蹤他的檔案。
    • 檢查檔案大小
      避免用戶上傳很大的檔案以進行 DOS 攻擊,我們可以設定 maximum 的 size。
    • 清理文件名稱
      超長文件名可能被濫用以利用 buffer overflow 的漏洞。同樣,名稱中帶有"特殊字符"的文件可能會導致奇怪的行為 (這具體取決於開發者如何處理它們)。
      -> 因此,在寫入磁盤之前,我們可以考慮讓文件經過清理。
    • 小心任何壓縮檔案
      有可能會有 zip bomb,通常惡意的 zip 程式經過精心設計,在解壓縮時可能會在 disk 中膨脹到很大。
    • 使用 Virus Scanner:
      如果可以的話,可以使用 Virus Scanner 先掃描用戶上傳的檔案。
  1. Input 的最終存入的位置與其權限為何?
  • 隔離你的上傳 (確保 Input 最終存入的位置與原本的 code 分開)

    可以考慮將 code 與上傳需要存儲的文件的地點分開 (將上傳的文件存儲在遠程文件服務器或單獨的磁盤分區中,也有助於隔離惡意文件可能造成的潛在損害。)

    或者,可以將上傳的文件寫入DB,避免直接去執行該文件。

  • 確保無法執行上傳文件

    無論最終存儲上傳文件的地點為何 (例如: 他是被寫入 disk),確保它們以操作系統知道且並不會將它們視為可執行代碼的方式寫入。

    換句話說,Web server process 應該對用於存儲上傳內容的目錄 "具有讀寫權限,但不應該能夠執行那裡的任何文件"

    以 NodeJS 為例,我們可以使用 fs 來確認 file 是否為 executable:

    const fs = require('fs');
    testFile = fs.statSync('test_file');
    // 使用 fs 的 StatSync,我們可以取得 testFile.mode (可以用 mode 確認他的檔案狀態)
    

    注意: 如果您使用的是基於 Unix 的操作系統,請確保上傳的文件在文件權限中沒有 executable 標誌。


今日小心得

來到了第三天,發現自己還需要訓練一下組織能力以及研究的速度,下班要重訓又要發文真的直接變成時間管理大師XD


Reference:


上一篇
Input (中篇)
下一篇
Redirects - 重新導向的資安漏洞們 (上篇)
系列文
從自建漏洞中學習 - 一起填坑吧30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言