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

例えば、コマンドラインで sha1pass を使って機密性の高いパスワードのハッシュを生成しているとしましょう。sha1pass mysecretを使ってmysecretのハッシュを生成することはできますが、mysecretがbashのヒストリに残ってしまうという欠点があります。このコマンドの最終目標を達成しつつ、プレーンテキストでmysecretを明らかにしない方法はないでしょうか。おそらくpasswd` 形式のプロンプトを使用することで、それを実現できるのではないでしょうか。

私はまた、どのようなコマンドに対しても機密データを渡すための一般化された方法にも興味があります。この方法は、センシティブなデータが引数として (例えば sha1pass のように) 渡されたときや、あるコマンドの STDIN で渡されたときに変更されるでしょう。

これを実現する方法はありますか?


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

  • Kusalananda&#39 の回答](https://unix.stackexchange.com/a/439510/7868) にあるように、理想的にはユーティリティのコマンドライン引数としてパスワードや秘密を与える必要はないでしょう。これは、彼が説明したように、いくつかの点で脆弱であり、STDIN で秘密の入力を受けることができる、より良く設計されたユーティリティを使用すべきです。
  • @vfbsilva's answer は、bash の履歴に保存されるのを防ぐ方法を記述しています。
  • @Jonathan's answer は、プログラムが STDIN で秘密のデータを受け取ることができる限り、これを達成するための完全に良い方法を記述しています。そのため、私はこの回答を受け入れることにしました。私のOPのsha1passは単なる例でしたが、議論はSTDINでデータを取るより良いツールが存在することを確立しました。 R.](https://unix.stackexchange.com/users/6342/r)が[彼の回答](https://unix.stackexchange.com/a/439519/7868)で指摘しているように、変数に対するコマンド展開の使用は*安全では*ありません*。

まとめると、私は @Jonathan's の回答 を受け入れました。なぜなら、あなたがよく設計され、よく動作するプログラムを持っていることを考えると、それが最善の解決策であるからです。 コマンドラインの引数としてパスワードやsecretを渡すことは基本的に安全ではありませんが、他の回答は単純なセキュリティの懸念を軽減する方法を提供しています。

理想的には、平文のパスワードをコマンドの引数としてコマンドラインに入力することは決してありません。そうすると、パスワードはコマンドの引数になり、コマンドラインの引数は 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

複数行の入力が必要な場合(上記では、最後に改行文字を含まない1行が渡されると仮定しています)、head コマンド全体を cat で置き換え、入力(somecommand 自体がファイルの終わりまで読むと仮定します)を Ctrl+D (改行文字を含む場合は Return に続く)で終了させます(含まない場合は2回です)。

これは、どのシェルを使っているかに関係なく動作します(Bourneやrcのようなシェルであれば)。

いくつかのシェルでは、コマンドの前にスペースがある場合、入力されたコ マンドを履歴ファイルに保存しないようにすることができます。これは通常 HISTCONTROLignorespace という値を設定する必要があります。 OpenBSD では、少なくとも bashksh でサポートされていますが、 ksh93dash などではサポートされていません。zshユーザーは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 
解説 (15)

このようにHISTCONTROLを設定した場合。

HISTCONTROL=ignorespace

のように設定し、コマンドの先頭にスペースを入れてください。

~$  mycommand

と入力すると、履歴に残りません。

解説 (0)

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

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

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

head -c-1 mysecret | sha1pass 
解説 (6)