获取隐藏的密码输入

390
你知道在Linux中,当你尝试进行某些Sudo操作时,它会要求你输入密码,但是在你输入时终端窗口不会显示任何内容(密码不会显示)吗?
在Python中是否有一种方法可以做到这一点?我正在编写一个需要敏感信息的脚本,并希望在输入时隐藏它。
换句话说,我想从用户那里获取密码而不显示密码。

针对Tkinter特定的解决方案(指的是Tkinter文本输入字段而不是标准输入),请参见https://dev59.com/HHE95IYBdhLWcg3wMrAB。 - Karl Knechtel
如果您特别希望在输入的每个字符中显示 * 或其他符号,请参见 https://dev59.com/b1sV5IYBdhLWcg3wwxSX(但这里的一些答案也涵盖了该情况)。 - Karl Knechtel
6个回答

542

可以工作,但是如何小心处理“黑客”呢?他们可能会复制脚本并注释掉需要用户密码的行。 - asf107
198
如果黑客能够编辑源代码,那么就有其他问题需要担心。 - DSM
22
请求密码的背后意图是为了让您传递它以进行身份验证(例如,我正在使用此功能请求密码以与在线服务器进行身份验证)。如果黑客注释掉该行,则程序将因为无法验证服务器而失败。使用getpass()的想法是为了防止任何人通过查看源代码来发现您的密码,并且当您输入密码时,没有人可以通过盯着屏幕读取密码来获取您的密码。 - ArtOfWarfare
小心使用getpass函数。当在不兼容的终端上运行时,它会显示密码,而文档并没有说明如何事先检查这一点(例如尝试其他方法来获取密码)或者直接失败而不是要求输入密码并回显到终端上。 - callegar

204
import getpass

pswd = getpass.getpass('Password:')

getpass 可在 Linux、Windows 和 Mac 上使用。


24
“Password: ”(冒号后有一个空格)是默认提示,因此通常在调用getpass.getpass()时无需指定它。 - J-L
1
getpass是一个标准库模块,自Python 2.5以来就存在。 - jocassid
2
这在IDLE中给我一个错误Warning (from warnings module): File "C:\Python27\lib\getpass.py", line 92 return fallback_getpass(prompt, stream) GetPassWarning: Can not control echo on the terminal. Warning: Password input may be echoed. ,但在命令提示符中运行良好,找到了原因在这里 - Oshada
getpass()在IDLE中无法使用。是否有其他方法可以在不使用getpass()的情况下实现此功能? - user9855996
要在 stderr 上显示提示信息(您还需要 import sys):getpass.getpass(<string>,sys.stderr) - Philip Kearns
1
@Brendan,如果你正在使用IDLE或其他IDE,请考虑使用from easygui import passwordbox,然后跟着password = passwordbox("Enter password:") - user697473

20

这段代码将会在每个字母的位置打印出一个星号。

import sys
import msvcrt

passwor = ''
while True:
    x = msvcrt.getch()
    if x == '\r':
        break
    sys.stdout.write('*')
    passwor +=x

print '\n'+passwor

14
这个只适用于Windows,但至少不会重复使用 getpass 的答案。 - Jean-François Fabre
6
无法处理退格键。 - Aykut Kllic
我不确定你的代码是针对Python 2.x还是3.x,但这在我的电脑上无法运行。我正在使用Python 3.x。我遇到的第一个错误是'passwor += x'行的TypeError。它说:“不能隐式地将字节对象转换为字符串”。我更改了该行,以便将x显式转换为字符串,例如:“password += str(x)”。但代码仍然无法正常工作。当我运行它时,它不会提示我输入,只会无限打印星号。 - Larper
1
@Larper 这是针对Python 2的,可以查看代码的最后一行。 - MilkyWay90
@MilkyWay90,为了使这段代码与Python 3兼容,需要进行一些修改。已经提交了修改后的代码编辑。希望能够通过审核 :) - Sagar
不要这样做...人们已经做过了... - anthony

4

更新@Ahmed ALaa的答案

# import msvcrt
import getch

def getPass():
    passwor = ''
    while True:
        x = getch.getch()
        # x = msvcrt.getch().decode("utf-8")
        if x == '\r' or x == '\n':
            break
        print('*', end='', flush=True)
        passwor +=x
    return passwor

print("\nout=", getPass())

msvcrt 仅适用于 Windows,但是 PyPI 中的 getch 应该可以在两种操作系统下使用(我仅在 Linux 上进行了测试)。 您还可以取消/注释两行代码,以使其适用于 Windows。


不要这样做...别人已经做过了...stackoverflow.com/a/67327327/701532 - anthony

3

您还可以使用pwinput模块,它适用于Windows和Linux。默认情况下,它将字符替换为“*”,并且退格键可用。

import pwinput

password = pwinput.pwinput(prompt='Password: ')

您可以选择传递不同的掩码字符。

import pwinput

password = pwinput.pwinput(prompt='Password: ', mask='')

请查看pwinput文档以获取更多信息。


1
这里是基于@Ahmed ALaa提供的代码的我的代码。
特点:
- 适用于长度为64个字符的密码 - 接受退格输入 - 输出*字符(DEC: 42 ; HEX: 0x2A)而不是输入字符
缺点:
- 仅适用于Windows
函数secure_password_input()在调用时将密码作为string返回。它接受一个密码提示字符串,该字符串将显示给用户以输入密码。
def secure_password_input(prompt=''):
    p_s = ''
    proxy_string = [' '] * 64
    while True:
        sys.stdout.write('\x0D' + prompt + ''.join(proxy_string))
        c = msvcrt.getch()
        if c == b'\r':
            break
        elif c == b'\x08':
            p_s = p_s[:-1]
            proxy_string[len(p_s)] = " "
        else:
            proxy_string[len(p_s)] = "*"
            p_s += c.decode()

    sys.stdout.write('\n')
    return p_s

不要这样做...别人已经做过了...stackoverflow.com/a/67327327/701532 - anthony
1
@anthony 我发现写一个带有标准导入的16行函数更明智。此外,我可以看到引擎下正在运行的内容,并根据需要进行自定义。 - Sagar
是的,你可以自定义它...但其他用户呢?从个人经验来看,即使处理星号也可能变得非常复杂,因为要处理控制字符、Unicode、删除行,甚至是简单的关闭回显(在输入开始处使用tab或退格键)。更好的方法是专注于使用“密码助手”,例如“system-ask-password”,它已经提供了“星号密码输入”。SSH和SUDO都可以做到这一点!然后用户可以选择自己的密码输入方式,无论是使用星号、密码管理器还是其他来源! - anthony

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接