如何将用户输入的密码存储在内存中,并在不再需要后将其安全擦除?
详细说明,目前我们有以下代码:
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完成吗?
答案 0 :(得分:39)
Python对内存的控制水平不高。接受它,继续前进。在调用del password
之后,您可以执行的最佳是mail.login
,这样就不会保留对密码字符串对象的引用。任何声称能够做到这一点的解决方案只会给你一种虚假的安全感。
Python字符串对象是不可变的;在创建字符串后,没有直接的方法来更改字符串的内容。 即使你能够以某种方式覆盖password
引用的字符串的内容(技术上可能使用愚蠢的ctypes技巧),仍然会有其他密码副本已在各种字符串操作中创建:
你必须以某种方式获得对所有这些字符串的引用并覆盖它们的内存。
答案 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)
答案 7 :(得分:-4)
将密码存储在列表中,如果只将列表设置为null,则会自动释放存储在列表中的数组内存。