Journey of a noob

Learn From Noobs

Bash: 隱藏用戶輸入/密碼

Posted at # Shell

Bash: 隱藏用戶輸入/密碼

有時,我們或者需要隱藏用戶輸入,令用戶的需入不會在終端機(terminal)中顯示,特別是當我們的 script 需要取得用戶密碼時。

tl;dr

1. read -s

我們可以使用 read 指今加上 -s 選項來讀取密碼,這樣我們的 script 就不會顯示出用戶輸入的密碼。

例如:

#!/bin/bash

read -s -p "Enter password: " password
echo
echo "password: $password"

範例輸出:

noob@learnfromnoobs:~$ ./input_password_read.sh
Enter password:
password: 123456

如想知道更多,請參閱 read --help

2. stty

我們可以使用 stty -echostty echo 包著我們用作取得用戶密碼的指令,這樣會關掉這些指令的 echo, 令這些指令不會有任何輸出。

例如:

#!/bin/bash

stty -echo
echo -n "Enter password: "
read password
echo
echo "password: $password"
stty echo

範例輸出:

noob@learnfromnoobs:~$ ./input_password_stty.sh
Enter password:
password: 123456

注意當我們輸入密碼時,我們是無法看到我們正在輸入甚麼的,上述兩個方法都會有同樣的結果。 就是這樣了!當然,千萬不要像菜鳥一樣使用 “123456” 作為密碼呀!


ts;wm

stty 是甚麼?

根據 stty 的 man page,stty 是一個用作改變並列印終端機(terminal)設置的工具。 如果我們不帶參數執行這指令,則會輸出波特率(baud rate),行的約束規則(line discipline number),以及與 stty sane 不同的設置。

noob@learnfromnoobs:~$ stty
speed 38400 baud; line = 0;
-brkint ixoff -imaxbel iutf8

我們可以試下把 echo 關掉,然後再次執行 stty,由於我們已經把 stty 關掉,所以當我們輸入 stty 時看不到自己打字是正常的,我們可以從 stty 最後一行的輸出中看到 “-echo”,表示 echo 已經被關掉。

noob@learnfromnoobs:~$ stty -echo
noob@learnfromnoobs:~$ speed 38400 baud; line = 0;
-brkint ixoff -imaxbel iutf8
-echo

我們更可以使用 stty -a 來查看 stty 現在所有的設置。

noob@learnfromnoobs:~$ stty -a
speed 38400 baud; rows 46; columns 104; line = 0;
intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = <undef>; eol2 = <undef>; swtch = <undef>;
start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R; werase = ^W; lnext = ^V; discard = ^O; min = 1; time = 0;
-parenb -parodd -cmspar cs8 -hupcl -cstopb cread -clocal -crtscts
-ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl ixon ixoff -iuclc -ixany -imaxbel
iutf8
opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
isig icanon iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt echoctl echoke -flusho
-extproc

如想知道更多,請參閱 man stty 或者 info stty

用星號顯示密碼

注意這個方法會暴露你的密碼長度,直接不顯示用戶的輸入會是個更好的方法,不過如果你真的想使用這個方法,你可以參考以下方式。

1. systemd-ask-password 如適用

如果你可以使用 systemd-ask-password 這個工具,你可以直接使用它來取得用戶密碼。 注意這工具有一個預設的 60 秒逾時,我們可以使用選項 --timeout=0 把逾時功能關掉。

#!/bin/bash

password=`systemd-ask-password "Enter password:"`
echo "password: $password"

範例輸出:

noob@learnfromnoobs:~$ ./input_password_systemd.sh
Enter password: ******
password: 123456

2. 自己寫吧

如果你不喜歡 systemd-ask-password 的方法(又或者你想用星號以外的其他符號),你可以寫一個自己的程式,這也是一個有趣的練習。

我們的程式應該要允許用戶修改輸入,因此我們的程式需要有處理 backspace 和 EOL 的能力,我們要小心用戶不能刪掉輸入提示(prompt)。

#!/bin/bash

unset password
unset chartCount

echo -n "Enter password: "

while IFS= read -r -n1 -s char; do
    case "$char" in
    $'\0')
        break
        ;;
    $'\177')
        if [ ${#password} -gt 0 ]; then
            echo -ne "\b \b"
            password=${password::-1}
        fi
        ;;
    *)
        chartCount=$((chartCount+1))
        echo -n '*'
        password+="$char"
        ;;
    esac
done

echo
echo "password: $password"

範例輸出:

noob@learnfromnoobs:~$ ./input_password_asterisk.sh
Enter password: ******
password: 123456

以上程式的小解釋:

  1. 我們在 while loop 中使用了 IFS=,否則如果用戶的密碼有空白符號,while loop 就會被中斷,如想知道更多,請參閱 man bash,搜尋 “IFS”。
  2. 我們在 read 指令中使用了選項 -r,這允許用戶使用含有 ’\’ 的密碼。
  3. echo -ne "\b \b" 是用作刪除密碼最後的一個字元, \b 把指標(cursor)向左移一格,然後我們輸出一個空白字元,最後再次用 \b 向左移一格,這就是刪除一個字元背後的完整動作;而選項 -e 則是用來使 echo 能解釋 ’\’ 的轉義功能。

總結

總結,我們一共提供了 4 個隱藏用戶輸入或者密碼的方法:

  1. 使用 read -s
  2. 使用 stty -echo
  3. 使用 systemd-ask-password
  4. 按自己需要寫適合自己的程式

無論你最後採用了哪個方法,我都希望你享受閱讀這篇文章。

記得要不斷學習,have fun!