安全地擦除磁盘/提示和技巧 - Arch Linux 中文维基

跳转到内容

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

来自 Arch Linux 中文维基
< 安全地擦除磁盘

翻译状态：

- 本文（或部分内容）译自 Securely wipe disk/Tips and tricks，最近一次同步于 2025-08-08，若英文版本有所更改，则您可以帮助同步与翻译更改的内容。
- 您可以在 ArchWiki 的对应页面找到本文翻译的原始修订历史。
- 本文可能与英文原文存在出入。

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

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

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

## 擦除单个文件

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

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

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

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

- 使用 `shred -x <目标文件>`， `-x`选项会用伪随机数据替换文件的内容，且不改变文件大小。`-u` 选项会在覆写后删除文件。
- 使用 `mkfs` 可以将文件格式化为文件系统，挂载该文件系统后，任何对文件系统的修改都将反映到文件上，在文件系统上存储其它内容，可达到覆盖原始文件内容的目的。
- `dd` 可创建指定大小、内容的文件，若目标文件已存在，则直接会覆写。通过组合 `skip` 和 `seek` 选项，可以将整个文件或文件的一部分替换为其他内容。在操作前，需要知道文件大小，以避免意外扩容文件。文件大小可以使用 `du -b <文件名> | cut -f1` 或 `stat -c "%s" <文件名>`获取。注意使用`dd`时，必须指定 `iflag=fullblock` 选项，详见 Dd#部分读取：复制的数据量小于要求的大小。
- 使用 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` 循环结合使用。

另见：

- 转换文本文件的字符集
- Advanced Bash-Scripting Guide - 描述使用 bash 脚本创建文件的高级方法
- sed alternatives - 一个 perl 示例，在替换文件内容方面比 sed 效果更好

## 覆写目标

### 防止擦除已挂载的分区

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

    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`的输入实现。此外，通过设置`skip` 和 `seek` 选项的值，还能确定要擦除的范围。除了例子中使用的`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 使用率。此外，也可以为模板文件创建压缩包，将压缩包复制到内存盘中，并使用能够将解压后的内容输出到标准输出的解压缩工具。使用压缩包的缺点是，难以在每次覆写时只是用压缩包中的部分模板文件。不过，使用压缩包也存在优点：若在创建压缩包时使用了分卷压缩，可以直接将某一分卷作为覆写内容覆写文件

另见：

- sector size - 文件创建和扇区大小

## 擦除可用空间

警告：若正在为块设备加密准备可用空间，不适合使用此方法。

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

- 将输出重定向到一个文件，而不是分区或设备。
- 在循环中，使用随机文件名或目录名创建多个文件副本（例如，使用`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.

分类：​

- 安全
- 文件系统

安全地擦除磁盘/提示和技巧
添加话题