Last Updated: 2023-11-07 11:24:34 Tuesday
-- TOC --
getpass是Python标准库中的一个小模块,基本上我们只会用到其中一个接口,接口名也叫getpass。调用此接口后,会在命令行提示用户输入密码(一个字符串),并且没有回显。
Python的另一个内置的提示用户输入的接口是input,哪为什么在输入密码的时候,要用getpass呢?
我绕了好大一圈来研究这个问题,为此还编写了一个开源工具autopass,下面是我对这个问题的回答和理解:
input的输入来自stdin,有回显;而getpass的输入必须来自tty(controlling terminal),无回显,更安全。
一般情况下,session都有一个controlling terminal,用来处理session中各个进程的输入和输出。默认情况下,stdin来自controlling terminal的用户输入。但是stdin的指向可以被改变,这就是重定向,因此读取stdin,不一定能够读取到用户输入。比如下面两行命令,stdin的输入来自命令行的字符串或某个文件:
$ echo 'abcde12345' | command
$ command < <filename>
有一些更加需要安全性的情况,特别是密码输入的时候,一些进程会强制读取tty,并且设置了不回显。比如ssh的密码输入,sudo的密码输入,还有本文涉及的主题,python的getpass输入,都是这样情况。通过重定向,不能实现自动密码输入,因为stdin已经被重定向了,tty或controlling terminal总在那里,读取stdin与读取tty,不是一回事儿。
开源小工具autopass,就是用来解决在进程要强制读取tty的时候,自动输入密码。
一般情况下,通过网络login后,我们得到的是一个pts,伪终端,而且还是slave。host那边有一个master对应。我们输入的字符,通过网络传递给master,master再通过网络返回给slave回显。
当然,master可以设置为不回显。
我们输入Ctrl-C,实际发送\x03,master收到后,向对应的前台进程,发出SIGINT信号。
我们输入Ctrl-D,实际发送\x04,master收到后,理解为pts已经关闭,发送SIGHUP给shell进程。
以上流程的说明,细节处并不严谨,但不影响我们理解原理。
getpass强制读取tty,并且不回显,跟ssh,sudo一样。
写一个脚本来测试强制读取tty:
$ cat test_readtty.py
f = open('/dev/tty', 'rb')
a = f.readline()
print(a)
$ python3 test_readtty.py
abce1234
b'abce1234\n'
$ $ echo 'abcd1234' | python3 test_readtty.py
56789
b'56789\n'
可以看出,echo命令的重定向无效,test_readtty.py中的代码,并没有去读stdin,这就是区别!
但上面的测试代码有回显,可以设置不回显,请参考getpass源码。
本文链接:https://cs.pynote.net/sf/python/202207301/
-- EOF --
-- MORE --