web-dev-qa-db-ja.com

任意のコマンドに対して、プロンプトを使用してbashで機密データを渡す方法はありますか?

コマンドラインでsha1passを使用して、機密性の高いパスワードのハッシュを生成するとします。 sha1pass mysecretを使用してmysecretのハッシュを生成できますが、これにはmysecretがbash履歴にあるという欠点があります。おそらくmysecretスタイルのプロンプトを使用することによって、passwdをプレーンテキストで表示しないようにしながら、このコマンドの最終目標を達成する方法はありますか?

機密データをコマンドに渡すためにこれを行う一般的な方法にも興味があります。機密データが引数(sha1passなど)として渡されるか、STDINでコマンドに渡されると、メソッドが変更されます。

これを達成する方法はありますか?


編集:この質問は多くの注目を集め、以下にいくつかの良い答えが提供されています。要約は次のとおりです。

  • @ Kusalanandaの回答 のとおり、理想的には、ユーティリティのコマンドライン引数としてパスワードやシークレットを指定する必要はないでしょう。これは、彼が説明したようにいくつかの点で脆弱です。STDINで秘密の入力を受け取ることができる、より優れた設計のユーティリティを使用する必要があります
  • @ vfbsilva's answer は、bashの履歴に物が保存されないようにする方法を説明しています
  • @ Jonathanの回答 は、プログラムがSTDINで秘密データを取得できる限り、これを達成するための完全に優れた方法を説明しています。そのため、この回答を受け入れることにしました。私のOPのsha1passは単なる例でしたが、STDINでデータを取得するためのより優れたツールが存在することがディスカッションで確認されました。
  • @ R .. 注記 彼の答え のように、変数でのコマンド展開の使用は安全ではありません

要約すると、私は @ Jonathanの答え を受け入れました。それは、うまく機能するように設計され、適切に動作するプログラムがある場合、それが最良の解決策だからです。コマンドライン引数としてパスワードまたはシークレットを渡すことは基本的に安全ではありませんが、他の回答は単純なセキュリティ上の懸念を軽減する方法を提供します。

42
cemulate

zshまたはbashシェルを使用している場合は、組み込みのreadシェルに-sオプションを使用して、端末デバイスからエコーせずに行を読み取ります。

IFS= read -rs VARIABLE < /dev/tty

その後、変数をstdinとして使用するために、いくつかの豪華なリダイレクトを使用できます。

sha1pass <<<"$VARIABLE"

誰かがpsを実行している場合、表示されるのは「sha1pass」だけです。

それはsha1pass引数が指定されていない場合、stdinからパスワードを読み取ります(行区切り文字を無視して1行で)。

22
Jonathan

理想的には、コマンドラインでクリアテキストのパスワードをコマンドの引数として入力しないでください。そうすることで、パスワードがコマンドの引数になり、psのような単純なツールを使用したり、一部の監査ログに記録したりして、コマンドライン引数がプロセステーブルに表示される場合があります。

そうは言っても、実際のパスワードをシェルのコマンド履歴から隠す方法は確かにあります。

sha1pass "$( head -n 1 )"

次に、パスワードを入力して押します Enter。ここで使用するheadコマンドは1行の入力のみを受け入れ、最後に入力する改行はsha1passに渡されるデータの一部にはなりません。

文字がエコーしないようにするには:

sha1pass "$( stty -echo; head -n 1; stty echo )"

stty -echoコマンドは、端末に入力された文字のエコーをオフにします。その後、エコーはstty echoで復元されます。

標準入力を渡すために、最後のコマンドを変更することができます(sha1passが標準入力でデータを受け入れた場合は、この特定のユーティリティが標準入力を無視しているように見えます):

{ stty -echo; head -n 1; stty echo; } | somecommand

複数行の入力が必要な場合(上記では、末尾に改行文字がない単一の行を渡す必要があると想定しています)、headコマンド全体をcatに置き換え、入力を終了します( somecommand自体がファイルの終わりまで読み取ると仮定) Ctrl+D (以下 Return 入力に改行文字を含めたい場合、含めない場合は2回)。

これは、使用しているシェルに関係なく機能します(ボーンのようなシェルまたはrcのようなシェルである限り)。

Someシェルは、コマンドの前にスペースが付いている場合、入力したコマンドを履歴ファイルに保存しないようにすることができます。これには通常、HISTCONTROLを値ignorespaceに設定する必要があります。これは、OpenBSDでは少なくともbashkshでサポートされていますが、 ksh93またはdashzshユーザーは、histignorespaceオプションまたはそのHISTORY_IGNORE変数を使用して、無視するパターンを定義できます。

端末に文字をエコーせずにreadでの読み取りをサポートするシェルでは、次のコマンドを使用することもできます

IFS= read -rs password     # -s turns off echoing in bash or zsh
                           # -r for reading backslashes as-is,
                           # IFS= to preserve leading and trailing blanks
sha1pass "$password"

ただし、これには明らかに、プロセステーブルのパスワードが明らかになる可能性があるという同じ問題があります。

ユーティリティが標準入力から読み取り、シェルが「here-strings」をサポートしている場合、上記を次のように変更できます

IFS= read -rs password
somecommand <<<"$password"

以下のコメントの要約:

  • コマンドラインで指定されたパスワードを使用してコマンドを実行すると、上記のすべてのコマンドが実行されますが、データをコマンドにパイプするものを除き、psを同時に実行しているすべてのユーザーにパスワードが表示される可能性があります。ただし、対話型シェルから実行された場合、上記のコマンドはいずれも、シェルの履歴ファイルに入力されたパスワードを保存しません。

  • クリアテキストのパスワードを読み取る適切に動作するプログラムは、標準入力から、ファイルから、または直接端末から読み取ることでそれを行います。

  • sha1passは、直接入力するか、なんらかの形式のコマンド置換を使用して、コマンドラインにパスワードを要求します。

  • 可能であれば、別のツールを使用してください。

37
Kusalananda

HISTCONTROLを次のように設定した場合:

HISTCONTROL=ignorespace

スペースでコマンドを開始します:

~$  mycommand

履歴には保存されません。

25
vfbsilva

機密データをパイプまたはヒアドキュメント経由で渡す:

command_with_secret_output | command_with_secret_input

または:

command_with_secret_input <<EOF
$secret
EOF

シークレットを(エクスポートされていない)シェル変数に含めても問題ありませんが、ヒアドキュメントとシェル内部でのみ、コマンドラインでこれらの変数を使用することはできません。

コメントでKusalanandaが述べたように、インタラクティブシェルでコマンドを入力している場合、ヒアドキュメントに入力した行はシェルの履歴に保存されるため、そこでパスワードを入力するのは安全ではありませんが、シークレットを含むシェル変数を使用しても安全です。履歴には、$secretに展開されたものではなく、テキスト$secretが含まれます。

コマンド展開の使用は安全ではありません

command_with_secret_input "$(command_with_secret_output)"

出力はコマンドラインに含まれ、ps出力(または手動で/ procから読み取る)に表示されるため、/ procが強化されたシステムを除きます。

変数への割り当ても問題ありません。

secret=$(command_with_secret_output)

値をファイルに書き込んで、ファイルを渡すだけです。

$ cat > mysecret
Big seecreeeet!
$ cat mysecret | sha1pass 

sha1passがどのように機能するかはわかりません。ファイルを入力として受け取ることができる場合は、sha1pass < mysecretを使用できます。そうでない場合、catを使用すると、最後の改行が含まれるため、問題になる可能性があります。その場合は、次を使用してください(head-cをサポートしている場合):

head -c-1 mysecret | sha1pass 
6
terdon

Terdonが実行できることが可能であれば、それが標準入力を通過する最良のソリューションです。残った唯一の問題は、彼がパスワードをディスクに書き込んだことです。代わりにこれを行うことができます:

stty -echo
echo -n "password: "
head -1 | sha1pass
stty echo

クサラナンダが言ったように、stty -echoは、もう一度stty echoを実行するまで、入力した内容が表示されないようにします。 head -1は、標準入力から1行を取得してsha1passに渡します。

1
JoL

私は使うだろう

sha1pass "$(cat)"

catEOFまでstdinから読み取りますが、これはCtrl + Dを押すことで発生する可能性があります。次に、結果は引数としてsha1passに渡されます。

0
oktupol