跳转到内容

安全地擦除磁盘/提示和技巧

来自 Arch Linux 中文维基


主文章请见 安全地擦除磁盘

本文额外介绍了一些擦除工具,可替代专用擦除工具,并加快擦除速度。

警告:某些文件系统的保留块不能通过创建文件的方式擦除,但可以使用工具 tune2fs 禁用。

擦除单个文件

[编辑 | 编辑源代码]
警告:如果曾对存储文件的分区进行了 碎片整理、调整大小或移动操作,或者文件曾在同一设备上被复制过,那么擦除效果将受到影响。若数据存储在加密容器上,并擦除整个加密容器,则文件恢复将变得困难得多,但加密可能会大幅降低 磁盘性能(除非使用硬件加密)。另见 安全地擦除磁盘#数据残留
注意:要在擦除时保留文件的访问和修改时间不变,在修改文件前先使用stat(1)获取文件当前的时间信息,之后可使用touch(1)手动修改文件时间。另请参阅不同文件系统对元数据和时间戳的支持情况

本节将介绍擦除单个文件的两种基本方法。此外,还有一种专门用于反取证的高级方法,其非常耗时,并且只能通过专用工具完成,本文不作介绍。

  • 在删除前用随机数据覆写,或在不改变文件大小的情况下用其他内容替换原内容。
  • 使用专用工具擦除文件和文件系统存储的元数据
    • 搜索整个磁盘,找到并清除已删除文件的残留部分,同时不对其它文件造成影响。

可以使用常见的 Linux 工具在不改变文件大小的情况下覆写文件:

  • 使用 shred -x <目标文件>-x选项会用伪随机数据替换文件的内容,且不改变文件大小。-u 选项会在覆写后删除文件。
  • 使用 mkfs 可以将文件格式化为文件系统,挂载该文件系统后,任何对文件系统的修改都将反映到文件上,在文件系统上存储其它内容,可达到覆盖原始文件内容的目的。
  • dd 可创建指定大小、内容的文件,若目标文件已存在,则直接会覆写。通过组合 skipseek 选项,可以将整个文件或文件的一部分替换为其他内容。在操作前,需要知道文件大小,以避免意外扩容文件。文件大小可以使用 du -b <文件名> | cut -f1stat -c "%s" <文件名>获取。注意使用dd时,必须指定 iflag=fullblock 选项,详见 dd#Partial read: copied data is smaller than requested
  • 使用 perl 工具可以用单个符号(symbol)替换文件内容,同时避免文件大小发生变化。

要擦除文件的元数据,可以不断创建新文件,直到填满分区,这将迫使文件系统覆盖旧的文件元数据条目,以存储新创建文件的条目。此外,也可以使用专用工具。详见#擦除可用空间

组合使用提到的文件创建和转换工具擦除文件内容,可达到避免文件被恢复、误导恢复工具及其使用者(可通过覆写随机数据或预先定义好的其它内容实现)的目的。具体的组合方式可依情况和需求而定。

注意:
  • 若存储文件的文件系统还有可用空间,则简单的覆写操作可能无法清除文件的某些部分。
  • 若要覆写特定文件的内容,同时确保该文件在硬盘上的逻辑位置不变,可以先创建一个或多个文件将文件所在分区填满,再使用合适的工具重写或替换目标文件的内容。不过,如果分区的可用空间很多,而要覆盖的文件很少,这会消耗大量时间。

例如:

使用Perl,用 . 替换文件中所有内容的:

$ perl -p -i -e 's\[^*]\.\g' <文件名>

使用dd

$ <覆盖内容> | dd bs=<目标文件大小(字节)> count=1 iflag=fullblock of=<目标文件> seek=0

或者,也可使用stdout重定向。这种方式在创建文件时速度更快,但无法使用 seek 选项来跳过目标文件中的某些部分:

$ <覆盖内容> | dd bs=<目标文件大小(字节)> count=1 iflag=fullblock > <目标文件>
提示:如果覆盖内容长度小于目标文件,需将其与下文介绍的 while 循环结合使用。

另见:

覆写目标

[编辑 | 编辑源代码]

防止擦除已挂载的分区

[编辑 | 编辑源代码]

选择要擦除的设备时需要格外小心,简单的拼写错误就可能导致错误的目标被擦除,从而损坏系统。为了降低风险,可以使用脚本来包装选定的擦除工具。例如:

if [[ -e "$1" && -b "$1" ]];then
NOT_safe="$(lsblk -o "NAME,MOUNTPOINT" ${1//[0-9]/} | grep -e / -e '\]')";
 if [[ -z "$NOT_safe" ]];then
# 在这里你可以使用任何擦除工具擦除目标
# 擦除目标由命令行传入,并存储在变量“$1”中
#
  else
  echo 'Not allowed to destroy if any of the partitions is mounted: '"$NOT_safe"
 fi
fi 

使用dd进行高级擦除

[编辑 | 编辑源代码]

在使用dd时,可以利用OpenSSL,使用随机密码进行AES加密,并将密文用于擦除目标,以实现随机擦除:

# DEVICE="/dev/sdX"
# PASS=$(tr -cd '[:alnum:]' < /dev/urandom | head -c128)
# openssl enc -aes-256-ctr -pass pass:"$PASS" -nosalt < /dev/zero | dd obs=64K ibs=4K of=$DEVICE oflag=direct status=progress

上述命令使用/dev/urandom生成128字节的加密密钥,并使用 CTR 模式的 AES-256 算法来加密 /dev/zero 的输出。相比直接使用伪随机源,使用加密算法可能可以获得更快的写入速度。最终设备将被 AES 密文填充。

上述命令将块大小设置为 64K,通常比默认的 512 字节更快。还可以尝试更大的块大小,以找到适合硬件的最佳传输速率。参考 [1]及其中的参考文献。

类似的方法还可参见 Dm-crypt/准备磁盘#dm-crypt_擦除空设备或分区

使用模板文件

[编辑 | 编辑源代码]

除了用零填充,还可以使用内容无关紧要的文件进行填充。若使用mkfs格式化了目标文件,需要挂载该文件系统,并使用特定内容填满该文件系统(可以使用无关紧要的文件,或相关工具生成的重复输出)。

一种方法是反复使用模板文件进行擦除,直到设备末尾。若使用此方法,当出现到达设备末尾的错误时,必须手动使用停止键 来中断 while 循环,因而不推荐使用:

$ while [ 1 -lt 2 ];do cat file1-to-use.as-template file2-to-use.as-template /tmp/templatefiles/* ;done > /dev/sd"XY"

若使用dd,如果通过选项正确设置了要擦除的大小,就可以安全地进行重复擦除,而不会出现空间不足的错误。这可通过将while循环产生的模板文件输出作为dd的输入实现。此外,通过设置skipseek 选项的值,还能确定要擦除的范围。除了例子中使用的cat外,还可以使用head(1)tail(1)将模板文件的部分内容输出到标准输出。

while [ 2 -gt 1 ]; do
 if [ -z "$(pidof dd)"  ];then
  break ;
 fi;
cat file1-to-use.as-template file2-to-use.as-template /tmp/templatefiles/* ;
done | dd of=/dev/sd"XY" seek=<起始扇区> bs=<扇区大小> count=<擦除扇区数量>
提示:若要重复覆写同一区域,可以在 while ... done | dd ... 外层新增一个循环,使用新增循环的循环变量,在每次循环中使用不同的模板文件进行覆写。
注意:如果用于覆写的预定义模板文件数量很多,可以利用 SquashFS 来压缩文件和文件夹,并存放到挂载的 内存盘 中。这样能最大限度地减少磁盘读取次数,但同时会增加 CPU 使用率。此外,也可以为模板文件创建压缩包,将压缩包复制到内存盘中,并使用能够将解压后的内容输出到标准输出的解压缩工具。使用压缩包的缺点是,难以在每次覆写时只是用压缩包中的部分模板文件。不过,使用压缩包也存在优点:若在创建压缩包时使用了分卷压缩,可以直接将某一分卷作为覆写内容覆写文件

另见:

擦除可用空间

[编辑 | 编辑源代码]
警告:若正在为块设备加密准备可用空间,不适合使用此方法。

可以通过以下几种方式擦除可用空间:

  • 输出重定向到一个文件,而不是分区或设备。
  • 在循环中,使用随机文件名或目录名创建多个文件副本(例如,使用cp),直到占满所有可用空间。
  • 使用带有文件加密功能的工具,并使用随机密码、随机文件名进行加密。某些文件压缩工具支持加密功能,且可以通过选项设置压缩方法、文件类型等,有的还支持分卷压缩。通过使用循环,在循环中随机设置压缩选项,可以用加密数据填满可用空间,以覆写以前的数据。
  • 使用专门用于擦除可用空间的程序,例如:

wipefreespace — 安全地擦除文件系统上的可用空间,以防止已删除的敏感数据被恢复。

https://sourceforge.net/projects/wipefreespace/ || wipefreespaceAUR

zerofree — 扫描并以零填充文件系统中的非零空闲块

https://frippery.org/uml/ || zerofreeAUR

使用 dd

[编辑 | 编辑源代码]

可以使用 dd 创建一个文件来填满可用空间:

dd if=<填充数据源> of=junk
sync
rm junk

<填充数据源> 可以是 /dev/urandom 随机流或 /dev/zero 全零流。

注意需要确保数据已同步到磁盘后,再删除该文件。

使用 7-Zip

[编辑 | 编辑源代码]
Password="$(dd if=/dev/random bs=128 count=1 iflag=fullblock)"
DestinationFile="$((${RANDOM/0/1}$(date "+%s")/${RANDOM/0/1}))"
7z a -t7z -mhe=on -p"${Password}" -mx=0 -v1m ${DestinationFile} source

所用选项的详细说明参见 7z --help

source 可以是一个包含随机数据的文件,也可以是一个设备(例如 /dev/urandom),或者另一个块设备或其上的分区(例如 /dev/sd"XY")。注意当使用块设备时,该块设备中不应含有敏感数据,并且,块设备中已在文件系统层面删除的数据也可能会被读取并压缩,以填充目标位置。

注意:
  • 不必设置压缩级别,只需将数据存储到压缩文件中即可,以最大限度地减少 CPU 使用率并更快地填满可用空间。
  • 如果使用单个文件作为源,可以将其放入 内存盘/tmp 文件夹。/tmp文件夹使用tmpfs,用于将文件存储到内存中,可加快读取速度。

借助 timeout 命令创建多个文件

[编辑 | 编辑源代码]

若在循环中使用timeout命令,并设置随机的等待时间。则timeout将在随机时间后中断文件的创建,从而使得创建的文件大小随机化。不过该方法速度较慢。

循环 中使用带有随机等待时间的 timeout 命令会中断命令,从而留下一个随机大小的文件。这是一种很慢的方法,但也是一种可行的替代方案。此外,对于文件名,可以在随机部分之前附加特定的预定义前缀。

AA=${RANDOM/0/1};
timeout $((AA/100)) cat /dev/urandom > filename${RANDOM}.tmp;

另见

[编辑 | 编辑源代码]
  • limits for the file creation on the different file systems.
  • meta-data in the filesystem may keep information about file after it was deleted.
  • forensic software uses meta-data to recovery and what need to do for wiping of the meta-data.