2017年5月10日 星期三

用 LUKS 加密虛擬裝置來實作 linux 軟體版碎紙機

碎紙機 電腦要送修, 或是舊硬碟要賣掉、壞掉的電腦/硬碟要回收嗎? 記得要先把資料銷毀才送出去! 實驗 [ 1 2] 顯示: 從 eBay 等等地方買來的二手硬碟當中, 有相當高的百分比其中還含有不該外洩的私密資料, 包含醫療及財務資訊、 私密相片等等。 不能只靠運氣期望拿到你的硬碟的人是個正人君子啊!

最基本的動作, 是刪除檔案, 或者乾脆毀掉硬碟分割。 不過這只毀掉檔案的頭或分割表, 資料可能都還在。 這只能防 (好奇但沒惡意的) 君子而不能防小人啊。 畢竟, 剛刪掉不久的檔案都有可能還可以用 testdisk foremost 救回來。

shred 指令就如它的名字所示, 可以把一個檔案的內容用 0 或亂數覆寫過去 (好幾次), 這比較安全一些。 但是如果你在掛載 ext3 檔案系統時採用了 data=journal 選項 (非預設), 那麼這招就行不通了。 對 zfs 還有很多其他較新的檔案系統也無效, 因為它可能只是找一塊新的未用空間填資料而已, 舊的資料還在硬碟某處需要用力找才找得到的地方。

比較安全的方法是以分割或整顆硬碟為單位而不要以個別檔案為單位, 用 dd < /dev/zero > /dev/sdz99 把整個分割 (甚或是整顆硬碟) 清空。 假設貴哥演壞人的話, 以我的程度而言, 到了這個地步, 就絕對沒辦法把原用戶的資料挖出來了。

但是 聽說 填 0 的毀滅效果並不徹底, 因為硬碟上還會有一些殘存的磁性, 有一些特殊的硬體工具可以勉強讀出一部分的 bits。

所以比較好的方法是亂填一些資料。 從 /dev/random 讀亂數來填有點太辛苦, 因為真正夠亂的亂數的產生速度很慢。 拿一些無關緊要的檔案來當作 dd 的來源, 應該就非常安全了。

用 LUKS 來模擬亂數 不過整篇文章沒有一個比較長的指令, 感覺好虛哦。 那就來為賦新辭強說愁一下吧。 假設想把 /dev/sdz99 上面所有的資料全部清空, 希望用夠亂的資料而不是 0 來填寫該分割。 這篇文章 提供一個技巧: 把 /dev/sdz99 拿來建立 LUKS -- 一個加密的虛擬裝置, 比方叫做 /dev/mapper/adios 好了。 (adios 這個名字是等一下我們自己任意取的) 這樣, 當你從 /dev/mapper/adios 寫入規律的資料時 (例如 0), 實際上寫到 /dev/sdz99 的會被 LUKS 加密而變成一堆看起來像亂數的東西。 做完之後再把金鑰丟掉, 那它就真的變成一堆沒有意義的亂數了。 建議先用 fdisk 把 /dev/sdz99 這個分割砍掉、 重建一個 20MB 的小分割來練習實驗, 比較省時間。

  1. 把 /dev/sdz99 清空: dd < /dev/zero > /dev/sdz99
  2. 查看 /dev/sdz99 的內容, 忽略 「全部是 0」 的所有列: xxd /dev/sdz99 | grep -v '0000 0000 0000 0000 0000 0000 0000 0000' | less 空無一物, 果然全部都變成 0 了。
  3. 把 /dev/sdz99 變成加密分割區: cryptsetup luksFormat /dev/sdz99 注意: 要打大寫的 YES, 被問兩次要設定什麼密碼, 才算成功。
  4. 用相同的指令再次查看 /dev/sdz99 的內容, 按大寫的 G 跳到最後面, 得知前面的 130k 左右 (0x20400) 出現了一些資料 (裡面包含金鑰); 後面都還是 0。
  5. 建立加密的虛擬裝置: cryptsetup open --type luks /dev/sdz99 adios 這裡的 adios 是自己隨意取的名稱。 做完之後, 會出現一個新的裝置 /dev/mapper/adios。 在這上面所建立的任何檔案系統, 要把任何資料寫入 /dev/sdz99之前, 都會被 LUKS 攔下來先加密一下。
  6. 不過我們並沒有要在 /dev/mapper/adios 上面建立加密的檔案系統, 只想把它填入亂數, 所以: dd < /dev/zero > /dev/mapper/adios
  7. 此時如果再查看 /dev/sdz99 的內容, 有可能還沒改變, 我猜是 cache 的關係。 下 cryptsetup close adios 解除關聯, /dev/mapper/adios 消失, cache 應該就會寫出去。
  8. 再用 xxd 查看, 在 less 裡面搜尋 "203f0:", 會看到從第 2MB 開始 (0x200000) 就都是亂數了。 事實上, 把 grep 後面的 -v 拿掉, 改成只顯示全 0 的列, 更容易確認第 2MB 以後沒有全 0 的列。
  9. 最後再用其他方式 (/dev/random 或不重要的壓縮檔) 把 /dev/sdz99 的最前面 2MB 變成亂數 (金鑰也就不見了), 那就大功告成囉!

真的套用時, 我會把檔案系統掛載起來, 每做 1G 就印一下進度及時間。 這樣不僅可以知道現在的進度, 而且中斷之後要再接續也比較方便。

#!/bin/bash
# mkfs -t ext4 /dev/mapper/adios
# mount /dev/mapper/adios /mnt/destroy
total=$(df --output=size /dev/mapper/adios | tail -n 1)
avail=$(df --output=avail /dev/mapper/adios | tail -n 1)
remaining=$(( (avail + total*0.05) / 1048576 ))
# https://wiki.archlinux.org/index.php/ext4#Reserved_blocks
# 5% of disk spcae is reserved
echo "remaining space to be filled: $remaining G"
for (( k=0; k<=$remaining+3; ++k)) ; do
    echo ; echo -n "$k " ; date
    dd bs=1048576 count=1024 < /dev/zero >> /mnt/destroy/zero
done

ArchLinux 的這篇 考慮得更周詳。

不過如果你的硬碟已經壞到完全無法讀寫, 可是又怕高手可以讀出裡面的資料, 那該怎麼辦呢? 很遺憾地, 文雅的手段是不夠的。 磁鐵無法刪除資料、 泡水也沒用。 據說浸在醋裡面可以刪資料。 但最有把握的, 還是暴力的手段, 例如用電鑽爆破或用氫氧化鈉把整顆硬碟溶化掉囉: (殘暴畫面,慎入!)

如果不想採取這麼激烈的手段, 最好還是趁硬碟還勉強可以讀寫時, 用本文所介紹的文雅方法來消除資料吧!

沒有留言:

張貼留言