【问题标题】:Python securely remove filePython 安全地删除文件
【发布时间】:2013-07-01 13:47:18
【问题描述】:

如何使用 python 安全地删除文件?函数os.remove(path) 只删除目录项,但我想安全删除文件,类似于苹果名为“Secure Empty Trash”的功能会随机覆盖文件。

什么函数使用这种方法安全地删除文件?

【问题讨论】:

  • 这不是编程语言的特性。这是文件系统/操作系统/存储设备的一个特性。
  • IIRC,Secure Erase Trash 实际上所做的是取消所有文件的链接,然后立即进行单遍随机擦除,然后在后台启动标准的 35 遍擦除。
  • 据我所知,由于 SSD(闪存)的工作方式,您只能覆盖 HDD 上的文件,而不是 SSD 上的文件。

标签: python file erase


【解决方案1】:

您可以使用srm 安全地删除文件。可以使用Python的os.system()函数调用srm。

【讨论】:

  • 出于所有常见原因,我会使用subprocess.check_call 而不是os.system。在生成 shell 时不需要性能损失、劫持潜力等,最好自动检查调用是否成功,而不是忘记手动执行并假设你已经安全擦除了文件,而实际上你还没有.
  • 这对我很有帮助。谢谢。
【解决方案2】:

您可以使用srm,当然,您始终可以轻松地在 Python 中实现它。请参阅wikipedia 以获取用于覆盖文件内容的数据。请注意,根据实际的存储技术,数据模式可能会有很大差异。此外,如果您的文件位于 log-structured file system 或什至具有写入时复制优化的文件系统(如 btrfs)上,您的目标可能是来自用户空间的 unachievable

在您完成对用于存储文件的磁盘区域的混搭后,删除带有os.remove() 的文件句柄。

如果您还想擦除文件名的任何痕迹,您可以尝试在同一目录中分配和重新分配一大堆随机命名的文件,但这取决于目录 inode 结构(线性、btree、哈希等)。 ) 可能很难保证您实际上覆盖了旧文件名。

【讨论】:

  • +1。但请注意,在某些平台/文件系统中,您可以从用户空间进行安全擦除,但只能使用 kernel/libc/fs 提供的一些特殊 API。这意味着使用srm 会起作用,但你用Python 编写的任何东西都不会(除非你ctypes 特殊的API)。
  • 同时,您的平台可能值得查看srm(或者,在没有它的平台上,至少有一些srm)。例如,OS X 10.8 的源代码非常简单,如果你懂 C 并且懂 fts(类似于 Python 的 os.walk);那里几乎没有其他棘手的事情。
【解决方案3】:

您可以非常轻松地在 Python 中编写一个函数来用随机数据覆盖文件,甚至可以重复,然后将其删除。像这样的:

import os

def secure_delete(path, passes=1):
    with open(path, "ba+") as delfile:
        length = delfile.tell()
    with open(path, "br+") as delfile:
        for i in range(passes):
            delfile.seek(0)
            delfile.write(os.urandom(length))
    os.remove(path)

不过,转至srm 可能会更快。

【讨论】:

  • 这是个好主意,但使用random.seed() 代替os.urandom(n) 是否有优势
  • os.urandom 可能会(很多)更快,因为您一次可以获得多个字节。您需要以块的形式生成随机数据(可能一次 256K 到 1MB),以避免需要将所有随机数据保存在内存中。这可能与srm 一样快。
  • 这不会像使用srm 那样安全,也可能不会那么快。 Gutman 算法已经标准化了几十年,这是有充分理由的。并且某些平台上的srm 将利用某些硬盘驱动器上的内置“安全擦除”。
  • 但是,srm 是仅在具有 srm 的平台上的解决方案。我的观点是,你没有理由不能在 Python 中实现任何你想要的安全擦除算法。我的例子并不意味着规范或任何东西,我什至没有测试它。
  • 很好,但 pylint 抱怨:"ba+" is not a valid mode for open. (bad-open-mode)
【解决方案4】:

所以至少在 Python 3 中使用@kindall 的解决方案我只是把它附加了。这意味着文件的全部内容仍然完好无损,并且每次传递都只是添加到文件的整体大小中。所以它最终变成了[原始内容][那个大小的随机数据][那个大小的随机数据][那个大小的随机数据],这显然不是想要的效果。

这个诡计对我有用。我在追加中打开文件以查找长度,然后在 r+ 中重新打开,以便我可以寻找到开头(在追加模式下,导致不良效果的原因似乎是实际上不可能寻找到 0)

所以看看这个:

def secure_delete(path, passes=3):
with open(path, "ba+", buffering=0) as delfile:
    length = delfile.tell()
delfile.close()
with open(path, "br+", buffering=0) as delfile:
    #print("Length of file:%s" % length)
    for i in range(passes):
        delfile.seek(0,0)
        delfile.write(os.urandom(length))
        #wait = input("Pass %s Complete" % i)
    #wait = input("All %s Passes Complete" % passes)
    delfile.seek(0)
    for x in range(length):
        delfile.write(b'\x00')
    #wait = input("Final Zero Pass Complete")
os.remove(path) #So note here that the TRUE shred actually renames to file to all zeros with the length of the filename considered to thwart metadata filename collection, here I didn't really care to implement

取消注释每次通过后检查文件的提示,当我测试它时看起来不错,但需要注意的是文件名不会像真正的 shred -zu 那样被粉碎

【讨论】:

    【解决方案5】:

    实施手动解决方案的答案对我不起作用。我的解决方法如下,好像还可以。

    import os
    
    def secure_delete(path, passes=1):
        length = os.path.getsize(path)
        with open(path, "br+", buffering=-1) as f:
            for i in range(passes):
                f.seek(0)
                f.write(os.urandom(length))
            f.close()
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-01-23
      • 1970-01-01
      • 2018-02-21
      • 2015-11-26
      • 2012-08-02
      • 1970-01-01
      • 2017-11-07
      相关资源
      最近更新 更多