安全擦除内存中的密码 (Python)
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/728164/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Securely Erasing Password in Memory (Python)
提问by maxyfc
How do you store a password entered by the user in memory and erase it securely after it is no longer need?
您如何将用户输入的密码存储在内存中,并在不再需要时安全删除?
To elaborate, currently we have the following code:
详细说明,目前我们有以下代码:
username = raw_input('User name: ')
password = getpass.getpass()
mail = imaplib.IMAP4(MAIL_HOST)
mail.login(username, password)
After calling the login
method, what do we need to do to fill the area of memory that contains password with garbled characters so that someone cannot recover the password by doing a core dump?
调用该login
方法后,我们需要做些什么来将包含密码的内存区域填充为乱码,从而无法通过核心转储来恢复密码?
There is a similar question, however it is in Java and the solution uses character arrays: How does one store password hashes securely in memory, when creating accounts?
有一个类似的问题,但它是在 Java 中,解决方案使用字符数组: 创建帐户时,如何将密码哈希安全地存储在内存中?
Can this be done in Python?
这可以在 Python 中完成吗?
回答by Miles
Python doesn't have that low of a level of control over memory. Accept it, and move on. The bestyou can do is to del password
after calling mail.login
so that no references to the password string object remain. Any solution that purports to be able to do more than that is only giving you a false sense of security.
Python 对内存的控制没有那么低。接受它,然后继续前进。您能做的最好的事情是del password
在调用之后执行,mail.login
这样就不会保留对密码字符串对象的引用。任何声称能够做更多事情的解决方案只会给您一种虚假的安全感。
Python string objects are immutable; there's no direct way to change the contents of a string after it is created. Even ifyou were able to somehow overwrite the contents of the string referred to by password
(which is technically possible with stupid ctypes tricks), there would still be other copies of the password that have been created in various string operations:
Python 字符串对象是不可变的;没有直接的方法可以在创建字符串后更改其内容。即使您能够以某种方式覆盖所引用的字符串的内容password
(这在技术上通过愚蠢的 ctypes 技巧是可能的),仍然会在各种字符串操作中创建密码的其他副本:
- by the getpass module when it strips the trailing newline off of the inputted password
- by the imaplib module when it quotes the password and then creates the complete IMAP command before passing it off to the socket
- 当 getpass 模块从输入的密码中去除尾随的换行符时
- 由 imaplib 模块引用密码,然后在将其传递给套接字之前创建完整的 IMAP 命令
You would somehow have to get references to all of those strings and overwrite their memory as well.
您必须以某种方式获取对所有这些字符串的引用并覆盖它们的内存。
回答by amcgregor
There actually -is- a way to securely erase strings in Python; use the memset C function, as per Mark data as sensitive in python
实际上,有一种方法可以在 Python 中安全地擦除字符串;使用 memset C 函数,根据在 python 中将数据标记为敏感
Edited to add, long after the post was made: here's a deeper dive into string interning. There are some circumstances (primarily involving non-constant strings) where interning does not happen, making cleanup of the string value slightly more explicit, based on CPython reference counting GC. (Though still not a "scrubbing" / "sanitizing" cleanup.)
编辑添加,在帖子发布很久之后:这是对字符串实习的更深入的探讨。在某些情况下(主要涉及非常量字符串)不会发生实习,这使得基于 CPython 引用计数 GC 的字符串值的清理更加明确。(虽然仍然不是“擦洗”/“消毒”清理。)
回答by zdan
If you don't need the mail object to persist once you are done with it, I think your best bet is to perform the mailing work in a subprocess (see the subprocessmodule.) That way, when the subprocess dies, so goes your password.
如果您不需要邮件对象在完成后保持不变,我认为您最好的选择是在子流程中执行邮件工作(请参阅子流程模块。)这样,当子流程死亡时,您的密码。
回答by heplat
This could be done using numpy chararray:
这可以使用 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[:] = ''
You would have to determine the maximum size of password, but this should remove the data when it is overwritten.
您必须确定密码的最大大小,但这应该会在数据被覆盖时删除数据。
回答by Erik Aronesty
The correct solution is to use a bytearray() ... which is mutable, and you can safely clear keys and sensitive material from RAM.
正确的解决方案是使用 bytearray() ... 它是可变的,您可以安全地从 RAM 中清除密钥和敏感材料。
However, there are some libraries, notably the python "cryptography" library that prevent "bytearray" from being used. This is problematic... to some extent these cryptographic libraries should ensure that onlymutable types be used for key material.
但是,有一些库,特别是防止使用“bytearray”的python“cryptography”库。这是有问题的……在某种程度上,这些加密库应该确保仅将可变类型用于密钥材料。
There is SecureString which is a pip module that allows you to fully remove a key from memory...(I refactored it a bit and called it SecureBytes). I wrote some unit tests that demonstrate that the key is fully removed.
有 SecureString 这是一个 pip 模块,它允许您从内存中完全删除密钥......(我对其进行了一些重构并将其称为 SecureBytes)。我编写了一些单元测试来证明密钥已完全删除。
But there is a big caveat: if someone's password is "type", then the word "type" will get wiped from all of python... including in function definitions and object attributes.
但是有一个很大的警告:如果某人的密码是“type”,那么“type”这个词将从所有 python 中删除......包括在函数定义和对象属性中。
In other words... mutating immutable types is a terrible idea, and unless you're extremely careful, can immediately crash any running program.
换句话说......改变不可变类型是一个糟糕的主意,除非你非常小心,否则可能会立即使任何正在运行的程序崩溃。
The right solution... never use immutable types for key material, passwords, etc. Anyone building a cryptographic library or routine like "getpass" should be working with a "bytearray" instead of python strings.
正确的解决方案......永远不要对密钥材料、密码等使用不可变类型。任何构建加密库或例程(如“getpass”)的人都应该使用“bytearray”而不是 python 字符串。
回答by nightm4re
Here: The following replaces the memory address bytes of the variable with zeros, then dereferencing the pointer to the memory location.
这里: 下面用零替换变量的内存地址字节,然后取消引用指向内存位置的指针。
Tested on Debian based systems.
在基于 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.
回答by Trey Stout
EDIT: removed the bad advice...
编辑:删除了不好的建议......
You can also use arrays like the java example if you like, but just overwriting it should be enough.
如果您愿意,您也可以像 java 示例一样使用数组,但只需覆盖它就足够了。
回答by AlbertoPL
Store the password in a list, and if you just set the list to null, the memory of the array stored in the list is automatically freed.
将密码存储在一个列表中,如果只是将列表设置为空,则会自动释放存储在列表中的数组的内存。