安全擦除磁盘
擦除磁盘是通过在每一位上写入新数据来完成的。
常见用例
擦除设备上剩余的所有数据
擦除设备上的所有数据最常见的用例是当设备将被放弃或出售时。设备上可能(未加密)留有数据,您希望防止简单的取证调查,而这仅凭例如 文件恢复 软件即可轻松完成。
如果您想快速擦除磁盘上的所有内容,/dev/zero 或简单的模式可以实现最高性能,而在某些情况下,充分的随机性可能是有益的,这将在 #数据残留 中讨论。
每次覆盖的位都提供了数据擦除的级别,不允许通过常规系统函数(如标准的 ATA/SCSI 命令)和硬件接口进行恢复。上述任何文件恢复软件都将需要专门针对专有存储硬件功能。
对于 HDD,如果不使用至少是未公开的驱动器命令或对设备的控制器或固件进行修改以使其读取例如重新分配的扇区(S.M.A.R.T. 已停止使用的坏块),则无法进行数据重建。
不同的物理存储技术存在不同的擦除问题。最值得注意的是,所有基于闪存的设备和较旧的磁存储(旧 HDD、软盘、磁带)。
为块设备加密做准备
为了在擦除区域内为 块设备加密 做准备,建议使用密码学强随机数生成器生成的 #随机数据(本文档后续将称之为 RNG)。
另请参阅 Wikipedia:随机数生成。
数据残留
另请参阅 Wikipedia:数据残留。即使在尝试删除或擦除数据后,数据的表示形式也可能仍然存在。
操作系统、程序和文件系统
操作系统、执行的程序或 日志文件系统 可能会将您的未加密数据复制到块设备中的各个位置。在写入普通磁盘时,这仅与上述内容之一相关。
如果数据可以在磁盘上精确找到并且从未被复制到其他地方,那么使用伪随机数据进行擦除可以彻底且快速地完成。
一个很好的例子是 cryptsetup 使用 /dev/urandom 来 擦除 LUKS 密钥槽。
硬件相关问题
闪存
写放大 和其他特性使得闪存(包括 SSD)成为可靠擦除的顽固目标。由于设备控制器芯片和操作系统之间存在大量的透明抽象,可见数据永远不会在原地被覆盖,擦除特定块或文件并不可靠。
其他“特性”,如透明压缩(所有 SandForce SSD)可以压缩您的零或重复模式,所以如果擦除速度快得离谱,这可能是原因。
拆卸闪存设备、焊下芯片并在没有控制器介入的情况下分析数据内容,使用 简单的硬件 即可轻松完成。数据恢复公司可以以低廉的价格完成。
更多信息请参见
标记的坏扇区
如果硬盘将扇区标记为坏扇区,它就会将其隔离,并且软件无法写入该区域。因此,完全覆盖将无法触及它。然而,由于块大小的原因,这些扇区理论上只会产生几 KiB 可恢复数据。
残余磁性
对于现代高密度存储设备,进行单次完全的零填充或随机数据覆盖,已无法恢复出任何数据。请注意,在当今时代,重复执行该操作已无必要。[1] 其他相反的论点仅指单个残留位,而重构字节模式在现实中通常是不可行的。[2] 另请参阅 [3]、[4] 和 [5]。
选择目标
使用 fdisk 查找用户有读取权限的所有读/写设备。
检查输出,寻找以 /dev/sdX 等设备开头的行。
这是格式化为启动 Linux 系统的 HDD 的示例
# 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 USB 闪存盘的另一个示例
# 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 Media(USB、CD、PXE 等)启动,或者使用脚本 防止因输入错误而擦除挂载的分区。
选择数据源
要擦除敏感数据,可以使用任何符合需求的模式。
零
在大多数情况下,使用 /dev/zero 或简单模式进行覆盖被认为是安全的。对于当今的 HDD,这被认为足以且快速地擦除磁盘。
但是,写入模式或归零速度异常快的驱动器可能正在进行透明压缩。显然,可以假设并非所有块都以此方式被擦除。一些 #闪存 设备具有“此特性”。
之后要设置块设备加密,应该用随机数据(参见下一节)擦除区域,以避免削弱加密。
随机数据
/dev/urandom 可以作为 Linux 内核的快速安全加密伪随机数据源。有关随机和伪随机数据源的更多详细信息,请参阅 随机数生成。
过去,当内核的随机数生成器很慢时,生成伪随机数据的常用替代方法是使用加密的数据流,例如通过使用随机密钥加密 /dev/zero。虽然这在理论上应该是安全的,但它不再比内核新的、更快的随机数生成器有任何优势,并且存在临时密钥意外保存在某处而导致风险。
选择块大小
另请参阅 Wikipedia:Dd (Unix)#块大小,块大小 io-limits。
如果您有 Advanced Format 硬盘,建议您指定一个大于默认 512 字节的块大小。为了加快覆盖过程,请选择与您的驱动器物理几何形状匹配的块大小,方法是在 dd 命令后附加块大小选项(即 bs=4096 用于 4 KiB)。
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
genwipe.sh /dev/sdXY。手动计算要擦除的块
块存储设备被划分为扇区,单个扇区的大小可以用来计算整个设备的字节大小。为此,将扇区数乘以驱动器扇区大小。
下面我们以 dd 命令的参数为例来擦除一个分区
# dd if=data_source of=/dev/sdX bs=sector_size count=sector_number seek=partitions_start_sector 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
- fdisk 输出的第一行显示了磁盘大小(以字节和逻辑扇区为单位)。
- 存储设备或分区的字节大小也可以通过命令
blockdev --getsize64 /dev/sdXY获得。 - fdisk 输出的 Units 行显示了单个逻辑扇区的大小;逻辑扇区大小也可以从字节数除以逻辑扇区数得出,这里使用:
echo $((2000398934016 / 3907029168))。 - 要了解物理扇区大小(以字节为单位,这将使其工作更快),我们可以使用下一行。
- 要获得以物理扇区为单位的磁盘大小,可以将磁盘的字节大小除以单个物理扇区的大小,这里是
echo $((2000398934016 / 4096)),
- 在下面的示例中,我们将使用逻辑扇区大小。
- 您甚至可以使用
dd命令擦除未分配的磁盘空间,方法是计算一个分区结束和下一个分区开始之间的差值。
要擦除分区 /dev/sdX1,例如可以使用逻辑扇区参数如下。
- 使用设备上分区的起始地址,通过
seek=参数
# dd if=data_source of=/dev/sdX bs=${BytesInSector} count=${End - Start} seek=${Start} status=progress
使用 Start=2048, End=3839711231 和 BytesInSector=512。
- 或者使用逻辑扇区中的分区大小
# dd if=data_source of=/dev/sdX1 bs=${BytesInSector} count=${LogicalSectors} status=progress
使用 LogicalSectors=3839709184。
或者,通过使用物理扇区来擦除整个磁盘
# dd if=data_source of=/dev/sdX bs=${PhysicalSectorSizeBytes} count=${AllDiskPhysicalSectors} seek=0 status=progress
使用 AllDiskPhysicalSectors=488378646 和 PhysicalSectorSizeBytes=4096。
sdXY 或 sdX)时,count= 选项不是必需的,但当它试图写入超出限制的区域时,它会显示“没有剩余空间”的错误。覆盖目标
您可以选择几种实用程序来覆盖驱动器。如果您只想擦除单个文件,安全擦除磁盘/技巧与窍门#擦除单个文件 有额外的注意事项,以及下面提到的实用程序。
通过重定向输出
重定向输出可用于创建文件、重写分区上的可用空间,以及擦除整个设备或其上的单个分区。此处的示例使用稀疏文件(sparse file)将设备置零,但如果需要随机擦除,可以改用 /dev/urandom。
请注意,coreutils 9.11 版本的 cat(支持 splice(2) 系统调用)在 tmpfs 上通过稀疏文件生成零数据的速度比 /dev/zero 或 dd 更快。
以下示例显示了如何通过重定向来自其他实用程序的 stdout 来重写分区或块设备
# truncate -s 1PB /tmp/huge; cat /tmp/huge > /dev/sdXY
cat: 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
另请参阅 dd 和 安全擦除磁盘/技巧与竅門#擦除单个文件。
of=... 选项指向目标驱动器而不是系统磁盘。通过向磁盘上的每个可寻址位置写入零字节来用 /dev/zero 流零填充磁盘。
# dd if=/dev/zero of=/dev/sdX bs=4096 status=progress
或者 /dev/random 流
# 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/Drive preparation#dm-crypt 特定方法,其中使用了 dm-crypt。
cp
文件复制命令 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 将显示进度条、已用时间和预计完成时间。将 选定的数据源 传递给 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
shred(来自 coreutils 包)是一个 Unix 命令,可用于安全删除单个文件或完整设备,使其只能通过专门的硬件极难恢复(如果可能的话)。默认情况下,shred 执行三次覆盖,在每次覆盖时向设备写入 伪随机数据。这可以减少或增加。
以下命令调用 shred 并使用默认设置,并显示进度。
# shred -v /dev/sdX
shred 也可以用于单个分区,例如,要擦除第一个分区,请使用 shred -v /dev/sdX1。
或者,可以指示 shred 只进行一次覆盖,使用来自例如 /dev/urandom 的熵,最后用零覆盖。
# shred --verbose --random-source=/dev/urandom -n1 --zero /dev/sdX
scrub
scrub 迭代地将模式写入文件或磁盘设备,使数据检索更加困难。
以下命令调用 scrub 并使用默认设置,在模式 1 下,使用符合 NNSA 政策信函 NAP-14.x 的模式覆盖目标设备。这是最有效的方法。
$ scrub /dev/sdX
以下命令调用 scrub 并使用默认设置,在模式 2 下,使用符合 NNSA 政策信函 NAP-14.x 的模式覆盖目标文件,将写入的字节四舍五入以填充最后一个文件系统块。请注意,此模式有一些注意事项,请参阅 手册 以获取更多详细信息。
$ scrub /path/to/file # where file is a regular file
以下命令调用 scrub 并使用默认设置,在模式 3 下,创建目录并用文件填充直到文件系统已满。然后使用符合 NNSA 政策信函 NAP-14.x 的模式擦除文件,将写入的字节四舍五入以填充最后一个文件系统块。请注意,此模式有一些注意事项,请参阅 手册 以获取更多详细信息。
$ scrub /path/to/dir # where dir is a new directory name.
有关进一步的使用和信息,请参阅 手册。
badblocks
来自 e2fsprogs 的工具 badblocks 能够执行破坏性的读写测试,从而有效地擦除设备。默认情况下,它执行四次覆盖,可能需要很长时间。
# badblocks -wsv /dev/device
hdparm
hdparm 支持 ATA Secure Erase,这在功能上等同于用零填充磁盘。然而,它由硬盘固件本身处理,并且包括“隐藏数据区域”。因此,它可以被视为现代的“低级格式化”命令。SSD 驱动器据报道在发出此命令后能恢复到出厂性能,但可能未被充分擦除(参见 #闪存)。
一些驱动器支持 **增强型安全擦除**,它使用制造商定义的独特模式。如果 hdparm -I 的输出显示 **增强型** 擦除的时间优势很大,那么该设备可能具有硬件加密功能,擦除将仅针对加密密钥进行。
有关使用 ATA Secure Erase 的详细说明,请参阅 固态驱动器/内存单元清除 和 Linux ATA Wiki。
blkdiscard
请参阅 固态驱动器/内存单元清除#blkdiscard 的常用方法