跳到主要內容區塊

計資中心電子報C&INC E-paper

技術論壇

應用DotNetZip保護上傳檔案的最後一步
  • 卷期:v0070
  • 出版日期:2024-09-20

作者:唐瑤瑤 / 臺灣大學計算機及資訊網路中心程式設計組程式設計師


為了滿足業務需求,我們需要讓使用者透過Web應用程式將檔案上傳至伺服器,然而這也引發了資訊安全和隱私保護的議題。

 

數位發展部在113年1月提供的隱私強化技術應用指引中指出資料存在三種狀態:靜態儲存(Data at Rest)、傳輸中(Data in Transit)、使用中(Data in Use)。且根據教育部「教育體系資通安全暨個人資料管理規範」所述:「施行單位應考量個人資料型態及風險等級,透過實施適當技術和施行單位面的安全控制措施,確保個人資料在處理、儲存和傳輸時均受到保護,免於遺失或毀損,且未經授權或非法處理。」

根據上個段落提示,施行單位應採取安全控制措施以保護個資,以下就是我們有關C# .NET檔案上傳、儲存和使用所採取的做法。此外並介紹DotNetZip這個class library(https://github.com/DinoChiesa/DotNetZip),進一步幫助我們達到檔案壓縮和加密等資料安全保護目標。

步驟1:用戶驗證。為提升安全性,用戶上傳檔案前進行身份驗證。

步驟2:僅允許特定檔案類型上傳。

步驟3:驗證檔案類型。除了限制檔案類型外,也要確保文件沒有被偽裝成允許的檔案類型。例如,攻擊者將.exe重命名為.docx。

步驟4:限制檔案大小。確保設置最大檔案大小和檔案名稱長度(如果可能,限制允許的字符),以防止潛在的服務中斷。

步驟5:隨機更改上傳的檔案名稱,使攻擊者無法使用檔案名稱來存取文件。

步驟6:將檔案壓縮並加密後儲存。

安裝方式:在Microsoft Visual Studio中打開,選擇工具->NuGet封裝管理員,搜尋DotNetZip並安裝最新版本即可開始使用。目前測試安裝的版本是V1.16.0。

相關程式碼及說明如下:

using Ionic.Zip;
//zip file  
try {
  using(var zip = new ZipFile()) {
    //檔名除了預設ASCII code編碼,設定替代的壓縮檔裡UTF8中文檔名
    zip.AlternateEncoding = System.Text.Encoding.UTF8;

    //其他選項有 ZipOption.Always
    zip.AlternateEncodingUsage = ZipOption.AsNecessary;

    //設定zip file密碼,若為null值表示無密碼。
    //這裡的密碼設定是指被加入壓縮的檔案(們),而非.zip壓縮檔本身。最終建立的存檔中的檔案名稱清單將以明文形式顯示,但個別檔案的內容已加密。這就是Zip加密的工作原理。
    zip.Password = "PASSWORD";

    //設定密碼時可同時明確設定加密 Encryption屬性,以指定如何加密新增至 ZipFile 的項目。如果將密碼設為非 null值且未設定加密 Encryption,則預設使用PKZip 2.0(「弱」)加密。這種加密相對較弱,但具有很強的互通性(在windows檔案總管即可解開)。如果將密碼設為null值,Encryption加密將重設為None。
    //在此我們使用using WinZip - compatible AES 256 - bit encryption. 
    //需要特別留意的是AES-encrypted ZIP file在windows檔案總管中只能看到內含之檔案列表,但無法將其解壓縮。
    zip.Encryption = EncryptionAlgorithm.WinZipAes256;

    //DotNetZip支援讀寫標準zip檔及ZIP64 zip檔。ZIP64 format是解除壓縮檔的size限制(larger than 4 GB)及檔案數量限制(more than 65534 entries in the archive)。
    //預設值為不開啟 Zip64Option.Never,但為避免壓縮後檔案過大出錯,比較保險的做法是設定為有需要時才開啟。
    zip.UseZip64WhenSaving = Zip64Option.AsNecessary;

    //第一個參數是欲加入壓縮的檔案(含路徑), 第二個參數是設定資料夾路徑。解壓縮時若不想產生任何子目錄,可以設定如下
    zip.AddFile(filename, @ "/");

    //或者直接從input stream 讀取。Create an entry in the ZipFile using the given Stream as input. The entry will have the given filename.
    ZipEntry ze = zip.AddEntry(name, MyFile.InputStream);
    //儲存壓縮檔。
    zip.Save(zipfilename);

    //檢查是否產生zip64的壓縮檔,若是,將傳回true。
    bool useZip64 = zip.OutputUsedZip64.Value;
  }
} catch (IOException IOe) {
  //處理錯誤
}
//zip end
 

解壓縮檔案相對單純,若有設定密碼則需要先設定。

//decompress
using(ZipFile zip = ZipFile.Read(zipfilename)) {
  //即使壓縮時使用AES Encryption,解壓縮時不需要再次設定。
  //但是zip檔的解壓縮密碼是必須的
  zip.Password = ”PASSWORD”;

  //解壓縮到指定的目錄
  zip.ExtractAll(path);
}
//end decompress

參考URL:https://documentation.help/DotNetZip/GettingStarted.htm