web-dev-qa-db-ja.com

bashでユーザー入力のパスワードをプログラムの標準入力の一部にする最も安全で簡単な方法は何ですか?

ユーザーがbashシェルプロンプトでパスワードを入力し、そのパスワードをプログラムのstdinの一部にするための(1)最も安全で(2)最も簡単な方法を探しています。

これはstdinがどのように見える必要があるかです:{"username":"myname","password":"<my-password>"}、 どこ <my-password>は、シェルプロンプトに入力されたものです。プログラムstdinを制御できれば、パスワードを安全に要求して適切な場所に配置するようにプログラムを変更できますが、ダウンストリームは標準的な汎用コマンドです。

以下を使用するアプローチを検討し、拒否しました。

  • コマンドラインにパスワードを入力するユーザー:パスワードは画面に表示され、「ps」を介してすべてのユーザーに表示されます
  • 外部プログラムの引数へのシェル変数補間(例:...$PASSWORD...):パスワードは引き続き「ps」を介してすべてのユーザーに表示されます
  • 環境変数(環境に残っている場合):パスワードはすべての子プロセスに表示されます。診断の一部としてコアダンプまたはダンプ環境変数をダンプする場合、信頼できるプロセスでもパスワードが公開される可能性があります
  • 長期間ファイルに保存されているパスワード、たとえ権限が厳しいファイルでも:ユーザーが誤ってパスワードを公開し、rootユーザーが誤ってパスワードを表示する可能性がある

私は現在の解決策を以下の回答として示しますが、誰かが考え出した場合、より良い回答を喜んで選択します。もっと単純なものがあるべきだと思います。あるいは、誰かが私が見逃したセキュリティの懸念を見ているかもしれません。

12
Jim Hoagland

bashまたはzshの場合:

unset -v password # make sure it's not exported
set +o allexport  # make sure variables are not automatically exported
IFS= read -rs password < /dev/tty &&
  printf '{"username":"myname","password":"%s"}\n' "$password" | cmd

IFS=がない場合、readは入力したパスワードから先頭と末尾の空白を削除します。

-rがないと、バックスラッシュを引用文字として処理します。

ターミナルからのみ読み取ることを確認したいとします。

echoは確実に使用できません。 bashzshにはprintfが組み込まれているため、コマンドラインがpsの出力に表示されません。

bashでは、$passwordを引用符で囲む必要があります。そうしないと、split + glob演算子が適用されます。

その文字列をJSONとしてエンコードする必要があるので、それはまだ間違っています。たとえば、少なくとも二重引用符とバックスラッシュは問題になります。これらの文字のエンコードについて心配する必要があるでしょう。プログラムはUTF-8文字列を期待していますか?端末は何を送信しますか?

zshを使用してプロンプト文字列を追加するには:

IFS= read -rs 'password?Please enter a password: '

bashの場合:

IFS= read -rsp 'Please enter a password: ' password
14

これが私が持っている解決策です(テストされています):

$ read -s PASSWORD
<user types password>
$ echo -n $PASSWORD | Perl -e '$_=<>; print "{\"username\":\"myname\",\"password\":\"$_\"}"'

説明:

  1. read -sは、画面にエコーしないでstdin(パスワード)の行を読み取ります。シェル変数PASSWORDに格納されます。
  2. echo -n $PASSWORDは、改行なしでパスワードをstdoutに書き込みます。 (echoはシェルの組み込みコマンドであるため、新しいプロセスは作成されないため、(AFAIK)echoの引数としてのパスワードはpsに表示されません。)
  3. Perlが呼び出され、stdinから$_にパスワードを読み取ります
  4. Perlは$_のパスワードをフルテキストに入れ、それを標準出力に出力します

これがHTTPS POSTの場合、2行目は次のようになります。

echo -n $PASSWORD | Perl -e '$_=<>; print "{\"username\":\"myname\",\"password\":\"$_\"}"' | curl -H "Content-Type: application/json" -d@- -X POST <url-to-post-to>
2
Jim Hoagland

お使いのバージョンのread-sをサポートしていない場合は、 この答え にあるPOSIX互換の方法を試してください。

echo -n "USERNAME: "; read uname
echo -n "PASSWORD: "; set +a; stty -echo; read passwd; command <<<"$passwd"; set -a; stty echo; echo
passwd= # get rid of passwd possibly only necessary if running outside of a script

set +aは、変数の環境への自動「エクスポート」を防止するためのものです。 sttyのmanページを確認してください。利用可能なオプションはたくさんあります。適切なパスワードにはスペースを含めることができるため、<<<"$passwd"が引用されています。 stty echoを有効にした後の最後のechoは、次のコマンド/出力を新しい行で開始することです。

0
dragon788