当我们从文件系统中删除文件时,数据不会被物理删除:操作系统只是简单地将文件先前占用的区域标记为空闲区域,并使其可用于存储新信息。确保实际从设备中删除数据的唯一方法是用其他数据覆盖它。出于隐私方面的考虑,我们可能希望执行此类操作(也许我们计划出售该设备,并希望确保新的拥有者无法访问我们的数据),或者在准备进行加密的设备。在本教程中,我们介绍一些工具,可用来完全擦除设备上的数据。类似经常被问到的问题是:
- Linux如何彻底删除文件?
- Linux文件粉碎?
- Linux数据粉碎?
在本教程中,您将学习:
- 如何使用dd粉碎数据
- 如何使用shred实用程序来安全擦除文件和设备
- 如何使用badblocks(坏块)覆盖数据
使用的软件要求和约定
类别 | 使用的要求,约定或软件版本 |
---|---|
系统 | 各Linux版本一般都支持 |
软件 | dd,shred或badblocks |
其他 |
|
约定 | #-要求linux命令可以直接以root用户身份或通过使用root特权以root特权执行sudo 命令
$ -要求linux命令以普通非特权用户身份执行 |
使用dd擦除数据
dd是一个非常强大的程序,默认情况下包含在所有主要的Linux发行版中。这里,我们要做的就是用零或随机数据覆盖某个块设备的内容。在这两种情况下,我们都可以使用”special”文件生成的数据:/dev/zero
和dev/urandom
(或者/dev/random
) 。前者每次对其执行读操作时都返回零。后者使用Linux内核随机数生成器返回随机字节。
要用零填充磁盘,我们可以运行:
$ sudo dd if=/dev/zero of=/dev/sdx
要使用随机数据,请执行以下操作:
$ sudo dd if=/dev/urandom of=/dev/sdx
使用LUKS容器作为随机数据生成器
使用随机数据覆盖设备是一项耗时的操作,但是在我们计划使用全盘加密以使磁盘的已使用和未使用部分无法区分时尤其有用。为了加快这一过程,我们可以使用一些技巧:我们可以在要随机填充的设备或分区上创建一个LUKS(Linux Unified Key Setup)容器
,并向其中写入零。由于加密,数据将随机透明地写入基础设备。
首先,我们创建LUKS
容器:
$ sudo cryptsetup luksFormat /dev/sdx
WARNING!
========
This will overwrite data on /dev/sdx irrevocably.
Are you sure? (Type uppercase yes): YES
Enter passphrase for /dev/sdx:
Verify passphrase:
在这种情况下,实际上不需要使用强密码,因为我们将容器用作随机数据生成器,并且在操作完成后将其清除。容器准备好后,我们通过运行以下命令将其打开:
$ sudo cryptsetup luksOpen /dev/sdx crypted
Enter passphrase for /dev/sdx:
现在容器已打开,我们可以使用dd并用零填充它。特别注意:我们写入LUKS容器的是映射的/dev/mapper/crypted
,而不是直接用底层/dev/sdx
设备:
$ sudo dd if=/dev/zero of=/dev/mapper/crypted bs=1M
写入所有数据后,我们关闭容器,并使用随机数据覆盖luks标头。标头的大小取决于使用的LUKS
:2MiB 对应
LUKS
格式,以及16MiB 对应
LUKS2
格式,后者已成为cryptsetup的最新版本中的默认格式。可以肯定的是,我们可以覆盖磁盘的前20MiB:
$ sudo cryptsetup luksClose /dev/mapper/crypted
$ sudo dd if=/dev/urandom of=/dev/sdx bs=1M count=20
使用shred擦除数据
该实用程序的名称很容易解释:如手册中所述,其主要目标是覆盖文件并有选择地删除它。shred
实用程序依赖于以下假设:文件系统会覆盖适当的数据。注意:
- 如果将应用程序安装在ext4等日志文件系统上(ext4可能是最常用的Linux文件系统)(使用data=journal选项),则该应用程序可能无法使我们获得预期的结果。
- 如果在挂载ext4文件系统时,使用
data=ordered或
data=writeback
选项(前者是默认选项),在这两种情况下shred
工作正常,会产生预期的结果。
在使用时data=journal
选项,不仅是元数据,而且数据本身在写入主文件系统之前也被写入文件系统日志。很容易看出为什么这会引起问题。
让我们看一些应用程序用法的例子。假设我们要安全删除一个名为”test”的文件。我们要做的就是运行以下命令(在这里我们使用-v选项
使程序输出更详细内容):
$ shred -v test
shred: test: pass 1/3 (random)...
shred: test: pass 2/3 (random)...
shred: test: pass 3/3 (random)...
默认情况下,应用程序用随机数据3次覆盖指定的文件。设置覆盖次数可以使用-n
(短缺--iterations
) 选项。要覆盖文件6次,我们将运行:
shred -v -n 6 test
shred: test: pass 1/6 (random)...
shred: test: pass 2/6 (000000)...
shred: test: pass 3/6 (555555)...
shred: test: pass 4/6 (ffffff)...
shred: test: pass 5/6 (aaaaaa)...
shred: test: pass 6/6 (random)...
在某些情况下,我们可能希望隐藏对文件或设备执行了粉碎操作的事实。在这种情况下,我们可以使用该程序的-z
(也就是--zero
)选项,以使程序在粉碎后执行附加一次写入零:
$ shred -v -n 6 -z test
shred: test: pass 1/7 (random)...
shred: test: pass 2/7 (ffffff)...
shred: test: pass 3/7 (aaaaaa)...
shred: test: pass 4/7 (555555)...
shred: test: pass 5/7 (000000)...
shred: test: pass 6/7 (random)...
shred: test: pass 7/7 (000000)...
从命令的详细输出中,我们确实可以注意到通过写入零来执行最后一遍覆盖(000000
)。我们可以通过运行hexdump
程序检查验证文件内容:
$ hexdump test
0000000 0000 0000 0000 0000 0000 0000 0000 0000
*
0008000
删除文件
如果在运行上面示例中的命令之一后看一下文件系统,我们会注意到尽管被随机数据覆盖,但文件本身并未被删除:发生这种情况是因为该命令可能用在了表示整个文件的设备或分区(例如,/dev/sda
),而它们不应该被删除。
但是,在处理通用文件时,我们可能还希望在覆盖文件后从文件系统中删掉文件。要实现此行为,我们可以使用-u
或者--remove
选项。这两个选项都会导致文件被删除,但是对于后者,我们还可以指定删除的方式。我们可以在以下两者之间进行选择:
- unlink:使用标准
unlink
系统调用删除文件; - wipe:删除前混淆文件名中的字节;
- wipesync:混淆的字节也同步到磁盘;
wipesync
模式是默认设置。
使用badblocks擦除数据
虽然badblocks
实用程序的主要目标是查找坏块
,但是通过其write-mode选项做破坏性测试,我们可以有效地覆盖和安全擦除设备上的现有数据。我们要做的就是启动命令并指定-w
选项:将通过先写入然后读取(在每个块上,0xaa
,0x55
,0xff
和0x00的数据模式)
并比较内容。我们可以使用-s
和-v
选项,分别使程序显示进度信息以及遇到的读取和写入错误的数量。结合这几点,要擦除设备数据,我们将运行:
$ sudo badblocks -wsv /dev/sdx
Checking for bad blocks in read-write mode
From block 0 to 3870719
Testing with pattern 0xaa: ^C6.30% done, 0:41 elapsed. (0/0/0 errors)
要运行上面的运行,应先卸载(unmount)设备,否则badblocks
将拒绝运行,除非使用-f
选项。一次测试的默认块数为64
;但是,我们可以使用-c
选项做修改。
结论
在本文中,我们看到了可用于在设备上粉碎数据的三个实用程序,以及一些用法示例。dd
和shred
是GNU核心工具集的一部分,因此几乎可以肯定它们已经安装在您的系统上。Badblocks
是用于测试不良块是否存在的软件:在执行read-write测试时,我们可以覆盖设备上的数据。
另外,请注意,数据粉碎的有效性还取决于所用设备的类型:例如,固态驱动器必须处理诸如写入放大率 的问题。