安全地擦除磁碟
擦除磁碟是通過向磁碟寫入新數據,直至將舊數據完全覆蓋完成的。
完全擦除磁碟最常見的應用是,在需要丟棄或出售設備時,清除磁碟上可能仍存在的未加密敏感數據。擦除數據後,可抵禦使用簡單文件恢復軟體恢復敏感數據的嘗試。
若追求擦除速度,可以向設備寫入/dev/zero產生的全零數據,或其它通過簡單模式生成數據。不過,在某些情況下,使用具有一定隨機性的數據可能更好,詳見#數據殘留。
對於設備已經被擦除的部分,不可能使用常規的系統功能(例如,標準ATA/SCSI命令)和硬體接口獲取到擦除前的數據。若文件恢復軟體需要嘗試從被擦除的部分恢復數據,則其必須使用依設備而異的專有功能。
對於機械硬碟,要從被擦除的部分恢復數據,至少需要使用非公開的設備指令,或修改設備控制器/固件,以從設備通常不可訪問的部分讀取信息。例如,可能可以從被重映射的扇區(記錄在S.M.A.R.T.中的設備損壞的扇區)讀取到擦除前的數據。
在擦除數據方面,不同的物理存儲技術存在不同問題。其中最值得注意的是基於快閃記憶體的設備和老式磁存儲設備(機械硬碟硬碟、軟盤、磁帶)。
若要將磁碟某部分用於存儲塊設備加密數據,建議使用密碼學隨機數生成器(下文中簡稱為RNG)生成的#隨機數據進行擦除。
另見Wikipedia:Random number generation。
即使有意移除/擦除了磁碟上的數據,數據的表示可能仍然存在於設備中,詳見Wikipedia:Data remanence。
作業系統、運行中的程序或日誌式文件系統,可能會在你不知情的情況下隱式將未加密數據分散拷貝到磁碟的任意角落。不過,只有當需要執行像前文提到的那種高級操作(例如為出售設備而徹底銷毀數據,或為全盤加密做準備)並直接操作整個磁碟時,這個潛在的風險才顯得至關重要。
若能準確地確定數據在磁碟上的位置,且能確定其並沒有被顯式或隱式地複製其它地方,可以通過向對應位置寫入偽隨機數據來快速、徹底地擦除數據。
例如,在擦除LUKS密鑰槽位時,cryptsetup就將向槽位所在位置寫入/dev/urandom產生的偽隨機數據。
由於快閃記憶體(包括固態硬碟)的寫放大等特性,可靠的擦除較為困難。
由於硬體控制器和作業系統之間的透明抽象層,在作業系統層面對數據的操作和控制器實際的操作可能完全不同。作業系統層面對數據的覆寫不會實際覆蓋快閃記憶體中的數據,因而難以可靠地擦除文件或設備上的特定數據塊。
此外,設備可能還提供其它功能,例如所有SandForce固態硬碟都啟用了透明壓縮。若使用全零或簡單重複性模式擦除,則設備可能將寫入壓縮。若發現擦除的速度遠超預期,可能是透明壓縮的作用。
使用較簡單的設備即可拆解快閃記憶體設備,直接不經設備控制器地讀取快閃記憶體上的數據,從而進行數據恢復。許多數據恢復公司都以較低價格提供對快閃記憶體的數據恢復服務。
更多信息詳見:
若硬碟將某一扇區標記為壞扇區,則其將隔離該扇區,使得不可能再通過軟體寫入該扇區。因此,即使在軟體層面進行了全盤寫入,該扇區的數據也不會被覆蓋。好在,由於扇區大小所限,壞扇區中理論可恢復的數據一般只有幾KiB。
對於現代高密度磁存儲設備,使用全零或隨機數據進行一次全盤寫入後,設備上就不再有任何有恢復意義的數據。因而,在如今,無需再進行多次擦除[1]。 雖然在磁碟上可能留下單個比特的磁性殘留痕跡,但將這些殘留痕跡組合成有意義的字節基本上是不可行的[2]。 另見[3]、[4]、[5]。
使用fdisk查找用戶具有讀取權限的所有設備。
在輸出中留意以/dev/sdX開頭的行。
例如,對於一個安裝了Linux系統的機械硬碟,輸出如下:
# fdisk -l
Disk /dev/sda: 250.1 GB, 250059350016 bytes, 488397168 sectors Units = sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 512 bytes / 512 bytes Disk identifier: 0x00ff784a Device Boot Start End Blocks Id System /dev/sda1 * 2048 206847 102400 83 Linux /dev/sda2 206848 488397167 244095160 83 Linux
對於寫入了Arch Linux引導鏡像的4GB U盤,輸出如下:
# fdisk -l
Disk /dev/sdb: 4075 MB, 4075290624 bytes, 7959552 sectors Units = sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 512 bytes / 512 bytes Disk identifier: 0x526e236e Device Boot Start End Blocks Id System /dev/sdb1 * 0 802815 401408 17 Hidden HPFS/NTFS
若擔心不小心損壞了計算機上的其它重要數據,可以考慮使用隔離的環境進行操作。例如,可以將要擦除的硬碟連接到虛擬環境(VirtualBox,VMWare,QEMU等),在虛擬環境中進行操作;或使用只連接了需要擦除的硬碟的單獨的計算機,並使用Live 介質(USB,CD,PXE等)啟動;也可使用腳本避免不小心擦除已掛載的設備。
在擦除敏感數據時,擦除數據源的數據模式應當符合要求。
在大多數情況下,使用/dev/zero或其它簡單數據模式擦除設備都是安全的。特別是對於現代機械硬碟,這是一種快速且恰當的擦除方式。
然而,若使用全零或簡單數據模式擦除的速度異常地快,說明設備可能使用了透明壓縮功能,此時很多磁碟塊可能並未被擦除。部分#快閃記憶體設備存在此問題。
若要將擦除的部分用於存儲加密數據,則不應當使用全零或其它簡單數據模式擦除,而應當使用隨機數據擦除(見下節),以避免削弱加密強度。
/dev/urandom的隨機數據由Linux內核生成,可作為快速且密碼學安全的偽隨機數來源。若要詳細了解隨機數和偽隨機數來源,參見隨機數生成。
曾經,內核的隨機數生成器速度較慢,因而常常使用加密數據流作為偽隨機數據來源。加密數據流通常通過使用隨機密鑰加密/dev/zero獲得。雖然加密數據流從理論上來講仍是安全的,但隨著內核隨機數生成器的改進,其相比直接使用內核隨機數生成器已經沒有任何優勢,且存在臨時隨機密鑰被意外保存的風險。
另見Wikipedia:Dd (Unix)#Block size,blocksize io-limits。
若使用的機械硬碟採用先進磁碟格式,推薦在擦除時手動設置塊大小,而不是默認的512位元組設置。採用符合硬碟物理扇區大小的設置,可提高擦除速度。可通過dd命令的bs選項設置塊大小(例如,bs=4096將設定塊大小為4KiB)。
可使用fdisk獲取設備的邏輯/物理塊大小。或者,也可以通過sysfs暴露的信息獲取:
/sys/block/sdX/size /sys/block/sdX/queue/physical_block_size /sys/block/sdX/queue/logical_block_size /sys/block/sdX/sdXY/alignment_offset /sys/block/sdX/sdXY/start /sys/block/sdX/sdXY/size
塊設備被劃分為扇區,可通過扇區數量乘扇區大小得到設備的大小。
例如,在使用dd命令擦除硬碟上的某一分區時,可按如下方式傳遞扇區數量、扇區大小等參數:
# dd if=<擦除数据源> of=/dev/sdX bs=<扇区大小> count=<扇区数量> seek=<分区起始扇区> status=progress
下面將使用具體實例進行闡述。對於/dev/sdX設備,fdisk的輸出如下:
# fdisk -l /dev/sdX
Disk /dev/sdX: 1.8 TiB, 2000398934016 bytes, 3907029168 sectors Disk model: ST3500413AS Units: sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 4096 bytes ... Device Boot Start End Sectors Size Id Type /dev/sdX1 2048 3839711231 3839709184 1,8T 83 Linux /dev/sdX2 3839711232 3907029167 67317936 32,1G 5 Extended
- 輸出的第一行顯示了設備大小(按字節計)、邏輯扇區數量。
- 此外,也可通過
blockdev --getsize64 /dev/sdXY獲取整個設備或設備上某一分區的大小。 - 輸出中「Units」開頭的行顯示了設備的邏輯扇區大小。也可通過設備大小(按字節計)除以邏輯扇區數量得到邏輯扇區大小(
echo $((2000398934016 / 3907029168)))。 - 輸出中「Sector size」開頭的行顯示了邏輯/物理扇區大小。使用物理扇區大小進行寫入,可提高速度。
- 可通過設備大小(按字節計)除以物理扇區大小得到物理扇區數量(
echo $((2000398934016 / 4096)))。
- 在本例中,將使用邏輯扇區大小進行擦除。
- 通過計算下一分區的起始扇區數與前一分區的結束扇區數的差值,可以使用
dd命令擦除未分區的磁碟空間。
例如,要擦除/dev/sdX1,並使用邏輯扇區大小作為擦除的塊大小:
- 使用要擦除的分區的起始扇區數、結束扇區數定位:
# dd if=<擦除数据源> of=/dev/sdX bs=${BytesInSector} count=${End - Start} seek=${Start} status=progress
根據fdisk的輸出,代入Start=2048,End=3839711231,BytesInSector=512即可。
- 或者,使用邏輯扇區數:
# dd if=<擦除数据源> of=/dev/sdX1 bs=${BytesInSector} count=${LogicalSectors} status=progress
根據fdisk的輸出,代入BytesInSector=512,LogicalSectors=3839709184即可。
也可以擦除整個設備,並使用物理扇區大小作為擦除的塊大小:
# dd if=<擦除数据源> of=/dev/sdX bs=${PhysicalSectorSizeBytes} count=${AllDiskPhysicalSectors} seek=0 status=progress
根據fdisk的輸出,代入AllDiskPhysicalSectors=488378646,PhysicalSectorSizeBytes=4096即可。
sdXY指定了分區的範圍時,無需手動指定count=選項。dd將寫滿整個區域,不過會在寫入結束時顯示剩餘空間不足的錯誤消息。可以使用多種工具對目標設備進行覆寫。若只需要擦除一個文件,參見安全地擦除磁碟/提示和技巧#擦除單個文件。
通過輸出重定向,可以創建文件、覆寫分區中的空閒空間、擦除單一分區或整個設備。下文的例子中使用/dev/zero以全零填充設備,若需要隨機擦除,應當改用/dev/urandom。
如下展示了如何將其它工具的標準輸出重定向到塊設備中,達到覆寫目的:
# cat /dev/zero > /dev/sdXY
cat: write error: No space left on device
# xz -z0 /dev/zero -c > /dev/sdXY
xz: (stdout): Write error: No space left on device
# dd if=/dev/zero status=progress > /dev/sdXY
dd: writing to 『standard output』: No space left on device 20481+0 records in 20480+0 records out 10485760 bytes (10 MB, 10 MiB) copied, 2.29914 s, 4.6 MB/s
dd在執行操作前不會二次確認。一定要仔細確認輸出指向了正確的設備或分區。確保of=...選項指向的是目標設備,而不是系統磁碟。使用/dev/zero全零流向磁碟每個可尋址位置寫入零:
# dd if=/dev/zero of=/dev/sdX bs=4096 status=progress
或者,使用/dev/urandom隨機流:
# dd if=/dev/urandom of=/dev/sdX bs=4096 iflag=fullblock status=progress
當dd提示No space left on device並結束時,表示擦除完成:
dd: writing to ‘/dev/sdX’: No space left on device 7959553+0 records in 7959552+0 records out 4075290624 bytes (4.1 GB, 3.8 GiB) copied, 1247.7 s, 3.3 MB/s
對於容量較大的目標設備,可參見如下提速技巧:
- 安全地擦除磁碟/提示和技巧#使用dd進行高級擦除 使用OpenSSL
- 安全地擦除磁碟/提示和技巧#使用模板文件 使用非隨機數據覆寫(例如,重複寫入一個文件的內容),隨機性不足,但速度快
- Dm-crypt/準備磁碟#dm-crypt_專用方案 使用dm-crypt
文件複製命令cp(1)不會檢查目標位置的類型,因而也可以用於覆寫設備:
# cp /dev/zero /dev/sdXY
cp: error writing 『/dev/sdXY』: No space left on device cp: failed to extend 『/dev/sdXY』: No space left on device
pv包工具可在覆寫時顯示進度條、已用時間、預計剩餘時間。將選定的擦除數據源作為參數傳遞給pv(1),並使用-o/--output選項指定要覆寫的目標。例如,使用/dev/zero全零填充/dev/sdX:
# pv /dev/zero -o /dev/sdX
wipe是wipe包的一部分,專門用於擦除文件。例如,要擦除特定目標:
$ wipe -r /path/to/wipe
參見wipe(1)。注意:該工具上次更新於2009年,其SourceForge 頁面顯示當前已處於不維護狀態。
shred是coreutils包的一部分。其專門用於安全地刪除單個文件或整個設備。被刪除的文件或設備即使理論上能夠被恢復,其難度也非常高,並且需要使用專用設備。默認情況下,shred將使用偽隨機數據執行3次覆寫操作。可手動指定覆寫操作執行的次數。
使用默認參數調用shred,這將在擦除時顯示進度條:
# shred -v /dev/sdX
shred也可用於擦除單個分區。例如,要擦除設備上的第一個分區,使用shred -v /dev/sdX1。
此外,也可設定只執行1次覆寫操作,選擇/dev/urandom作為熵源,並在結束前再使用全零覆蓋一次:
# shred --verbose --random-source=/dev/urandom -n1 --zero /dev/sdX
scrub將按指定的順序,用不同的模式多次覆蓋文件或設備,使得數據恢復更加困難。
如下命令使用默認參數調用scrub,覆寫整個設備(模式1)。覆寫使用的模式組合遵循NNSA Policy Letter NAP-14.x規範。這是效率最高的方式。
$ scrub /dev/sdX
如下命令使用默認參數調用scrub,覆寫特定文件(模式2)。覆寫使用的模式組合遵循NNSA Policy Letter NAP-14.x規範。實際覆寫的字節數將向上取整到能夠完全覆蓋文件占用的最後一個文件系統塊。注意,使用該模式時有一些需要注意的地方,詳見手冊。
$ scrub /path/to/file # file是常规文件
如下命令使用默認參數調用scrub,此時將創建一個目錄,在目錄中創建文件直到占滿文件系統,之後再覆寫創建的文件(模式3)。覆寫使用的模式組合遵循NNSA Policy Letter NAP-14.x規範。對於每一個文件,實際覆寫的字節數將向上取整到能夠完全覆蓋文件占用的最後一個文件系統塊。注意,使用該模式時有一些需要注意的地方,詳見手冊。
$ scrub /path/to/dir # dir是目录
更多信息和用法,參見手冊。
badblocks是e2fsprogs包的一部分,其通過反覆向設備寫入、讀取數據檢測壞扇區。由於其寫入操作對存儲的數據而言是破壞性的,因而也能用於擦除設備。在默認情況下,其將執行4次讀取、寫入循環,因而可能需要花費較長時間。
# badblocks -wsv /dev/device
hdparm支持ATA Secure Erase功能,該功能由設備固件處理,作用大致相當於使用全零填充整個設備,並包括軟體無法訪問的區域。其相當於現代版本的「低級格式化」命令。對於固態硬碟,有報道稱執行該命令後,性能可恢復到出廠水平,但可能不足以完全擦除數據(參見#快閃記憶體)。
某些設備支持Enhanced Secure Erase功能,其具體實現方式依廠商而異。若hdparm -I的輸出顯示,使用Enhanced Secure Erase相比普通Secure Erase的用時顯著更短,則說明設備可能支持硬體加密功能,而Enhanced Secure Erase將通過擦除加密密鑰保護數據安全。
有關ATA Secure Erase的更多信息,參見固態硬碟/存儲單元擦除、Linux ATA wiki。