安全擦除内存中的密码(Python)

时间:2009-04-08 01:13:21

标签: python security passwords

如何将用户输入的密码存储在内存中,并在不再需要后将其安全擦除?

详细说明,目前我们有以下代码:

username = raw_input('User name: ')
password = getpass.getpass()
mail = imaplib.IMAP4(MAIL_HOST)
mail.login(username, password)

在调用login方法之后,我们需要做些什么来填充包含带有乱码的密码的内存区域,以便有人无法通过核心转储来恢复密码?

有一个类似的问题,但它是在Java中,解决方案使用字符数组: How does one store password hashes securely in memory, when creating accounts?

可以用Python完成吗?

8 个答案:

答案 0 :(得分:39)

Python对内存的控制水平不高。接受它,继续前进。在调用del password之后,您可以执行的最佳mail.login,这样就不会保留对密码字符串对象的引用。任何声称能够做到这一点的解决方案只会给你一种虚假的安全感。

Python字符串对象是不可变的;在创建字符串后,没有直接的方法来更改字符串的内容。 即使你能够以某种方式覆盖password引用的字符串的内容(技术上可能使用愚蠢的ctypes技巧),仍然会有其他密码副本已在各种字符串操作中创建:

  • 通过getpass模块剥离输入密码的尾随换行符
  • 由imaplib模块引用密码,然后在将其传递给套接字之前创建完整的IMAP命令

你必须以某种方式获得对所有这些字符串的引用并覆盖它们的内存。

答案 1 :(得分:19)

实际上有一种方法可以安全地删除Python中的字符串;根据{{​​3}}

使用memset C函数

在帖子发布很久之后编辑添加:Mark data as sensitive in python。在某些情况下(主要涉及非常量字符串),其中不会发生实习,基于CPython引用计数GC,使字符串值的清理稍微更明确。 (虽然仍然不是“擦洗”/“消毒”清理。)

答案 2 :(得分:6)

如果您完成后不需要邮件对象保留,我认为您最好的选择是在子进程中执行邮件工作(请参阅subprocess模块。)这样,当子进程死了,所以你的密码。

答案 3 :(得分:1)

这可以使用numpy chararray完成:

import numpy as np

username = raw_input('User name: ')
mail = imaplib.IMAP4(MAIL_HOST)
x = np.chararray((20,))
x[:] = list("{:<20}".format(raw_input('Password: ')))
mail.login(username, x.tobytes().strip())
x[:] = ''

您必须确定密码的最大大小,但这应该在覆盖时删除数据。

答案 4 :(得分:1)

正确的解决方案是使用可变的bytearray()...,您可以安全地从RAM中清除密钥和敏感内容。

但是,有一些库,特别是阻止使用“ bytearray”的python“ cryptography”库。这是有问题的...在某种程度上,这些密码库应确保仅 可变类型用于密钥材料。

有一个SecureString,这是一个pip模块,允许您从内存中完全删除一个密钥...(我对其进行了重构,并将其称为SecureBytes)。我写了一些单元测试来证明密钥已完全删除。

但是有一个很大的警告:如果某人的密码是“ type”,那么“ type”一词将从所有python中删除...包括函数定义和对象属性。

换句话说,改变不可变类型是一个糟糕的主意,除非您非常小心,否则可能立即使任何正在运行的程序崩溃。

正确的解决方案……永远不要对密钥材料,密码等使用不可变的类型。任何构建密码库或“ getpass”之类的例程的人都应该使用“ bytearray”而不是python字符串。

答案 5 :(得分:0)

在这里:以下代码将变量的内存地址字节替换为零,然后取消对指向内存位置的指针的引用。

在基于Debian的系统上测试。

import sys 
import ctypes

def nuke(var_to_nuke):
    strlen = len(var_to_nuke)
    offset = sys.getsizeof(var_to_nuke) - strlen - 1
    ctypes.memset(id(var_to_nuke) + offset, 0, strlen)
    del var_to_nuke               # derefrencing the pointer.

答案 6 :(得分:-4)

编辑:删除了不好的建议......

如果您愿意,也可以使用java示例之类的数组,但只需覆盖它就足够了。

http://docs.python.org/library/array.html

答案 7 :(得分:-4)

将密码存储在列表中,如果只将列表设置为null,则会自动释放存储在列表中的数组内存。