コマンドラインでsha1pass
を使用して、機密性の高いパスワードのハッシュを生成するとします。 sha1pass mysecret
を使用してmysecret
のハッシュを生成できますが、これにはmysecret
がbash履歴にあるという欠点があります。おそらくmysecret
スタイルのプロンプトを使用することによって、passwd
をプレーンテキストで表示しないようにしながら、このコマンドの最終目標を達成する方法はありますか?
機密データをコマンドに渡すためにこれを行う一般的な方法にも興味があります。機密データが引数(sha1pass
など)として渡されるか、STDINでコマンドに渡されると、メソッドが変更されます。
これを達成する方法はありますか?
編集:この質問は多くの注目を集め、以下にいくつかの良い答えが提供されています。要約は次のとおりです。
sha1pass
は単なる例でしたが、STDINでデータを取得するためのより優れたツールが存在することがディスカッションで確認されました。要約すると、私は @ Jonathanの答え を受け入れました。それは、うまく機能するように設計され、適切に動作するプログラムがある場合、それが最良の解決策だからです。コマンドライン引数としてパスワードまたはシークレットを渡すことは基本的に安全ではありませんが、他の回答は単純なセキュリティ上の懸念を軽減する方法を提供します。
zsh
またはbash
シェルを使用している場合は、組み込みのread
シェルに-sオプションを使用して、端末デバイスからエコーせずに行を読み取ります。
IFS= read -rs VARIABLE < /dev/tty
その後、変数をstdinとして使用するために、いくつかの豪華なリダイレクトを使用できます。
sha1pass <<<"$VARIABLE"
誰かがps
を実行している場合、表示されるのは「sha1pass」だけです。
それはsha1pass
引数が指定されていない場合、stdinからパスワードを読み取ります(行区切り文字を無視して1行で)。
理想的には、コマンドラインでクリアテキストのパスワードをコマンドの引数として入力しないでください。そうすることで、パスワードがコマンドの引数になり、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では少なくともbash
とksh
でサポートされていますが、 ksh93
またはdash
。 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 <<<"$password"
以下のコメントの要約:
コマンドラインで指定されたパスワードを使用してコマンドを実行すると、上記のすべてのコマンドが実行されますが、データをコマンドにパイプするものを除き、ps
を同時に実行しているすべてのユーザーにパスワードが表示される可能性があります。ただし、対話型シェルから実行された場合、上記のコマンドはいずれも、シェルの履歴ファイルに入力されたパスワードを保存しません。
クリアテキストのパスワードを読み取る適切に動作するプログラムは、標準入力から、ファイルから、または直接端末から読み取ることでそれを行います。
sha1pass
は、直接入力するか、なんらかの形式のコマンド置換を使用して、コマンドラインにパスワードを要求します。
可能であれば、別のツールを使用してください。
HISTCONTROL
を次のように設定した場合:
HISTCONTROL=ignorespace
スペースでコマンドを開始します:
~$ mycommand
履歴には保存されません。
機密データをパイプまたはヒアドキュメント経由で渡す:
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
Terdonが実行できることが可能であれば、それが標準入力を通過する最良のソリューションです。残った唯一の問題は、彼がパスワードをディスクに書き込んだことです。代わりにこれを行うことができます:
stty -echo
echo -n "password: "
head -1 | sha1pass
stty echo
クサラナンダが言ったように、stty -echo
は、もう一度stty echo
を実行するまで、入力した内容が表示されないようにします。 head -1
は、標準入力から1行を取得してsha1pass
に渡します。
私は使うだろう
sha1pass "$(cat)"
cat
はEOF
までstdinから読み取りますが、これはCtrl + Dを押すことで発生する可能性があります。次に、結果は引数としてsha1pass
に渡されます。