作者:唐瑤瑤 / 臺灣大學計算機及資訊網路中心程式設計組程式設計師
為了滿足業務需求,我們需要讓使用者透過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