エコーを使用して機密データをchpasswdに渡すことは安全ですか?


17

私は大量にしようとしています使用して、いくつかのユーザーアカウントのパスワードを設定しますchpasswd。パスワードはランダムに生成され、出力されるstdout必要があります(書き留めるか、パスワードストアに保存する必要があります)chpasswd

素朴に、私はこれをこのようにします

{
  echo student1:$(head /dev/urandom | tr -dc A-Za-z0-9 | head -c 13 ; echo '')
  echo student2:$(head /dev/urandom | tr -dc A-Za-z0-9 | head -c 13 ; echo '')
} | tee >(chpasswd)

ただしecho、引数は通常他のユーザーに表示されるため、コマンドライン引数として新しいパスワードを渡すことを心配していますps -aux(ただし、にはecho行が表示されていませんps)。

返されたパスワードに値を追加してからそれを渡す別の方法はありますchpasswdか?


6
echo組み込みのシェルです。プロセステーブルには表示されません。
クサラナナンダ

回答:


15

あなたのコードはechoシェル組み込みなのでプロセステーブルに表示されないので安全でなければなりません。

代替ソリューションは次のとおりです。

#!/bin/bash

n=20
paste -d : <( seq -f 'student%.0f' 1 "$n" ) \
           <( tr -cd 'A-Za-z0-9' </dev/urandom | fold -w 13 | head -n "$n" ) |
tee secret.txt | chpasswd

これにより、nどのコマンドのコマンドラインでもパスワードを渡すことなく、生徒の名前とパスワードが作成されます。

このpasteユーティリティは、複数のファイルを列として結合し、それらの間に区切り文字を挿入します。ここでは:、区切り文字として使用し、2つの「ファイル」(プロセス置換)を指定します。最初のものには、seq20人の学生のユーザー名を作成するコマンドの出力が含まれ、2番目には、長さ13の20個のランダムな文字列を作成するパイプラインの出力が含まれます。

すでに生成されたユーザー名を持つファイルがある場合:

#!/bin/bash

n=$(wc -l <usernames.txt)

paste -d : usernames.txt \
           <( tr -cd 'A-Za-z0-9' </dev/urandom | fold -w 13 | head -n "$n" ) |
tee secret.txt | chpasswd

これらはsecret.txt、生成されたパスワードを端末に表示する代わりに、パスワードとユーザー名をファイルに保存します。


2
それは必要ありません巧妙なソリューションですechoprintf、しかしコードが解読は少し厄介です
ニルス・ヴェルナー

@NilsWernerもう少し説明を追加しました。あなたが私に拡大してほしい特定の事があるかどうか私に知らせてください。
クサラナナンダ

1
echoただし、シェルの組み込みに依存するべきではありません。ほとんどのシェルではそうですが、そのような要件はまったくありません。
オースティンヘメルガルン

1
@Kusalanandaちょうど好奇心が強い、との間には効果的な違いがtee secret.txt > >(chpasswd)ありtee secret.txt | chpasswdますか?後者の方がはるかに一般的であるため、プレーンパイプの代わりにプロセス置換を使用することを選択した理由を疑問に思っています
Christopher Shroba

1
@ChristopherShroba既に問題になっているコードと似ている以外の理由はありません(とのプロセス置換を使用tee)。あなたがそれを指摘したので、私は実際にそれを変更すると思います(それはより良く見えます)。ありがとう。
クサラナンダ

8

echoシェルに組み込まれている可能性が非常に高いためps、別のプロセスとして表示されません。

ただし、コマンド置換を使用する必要はありません。パイプラインからの出力を直接取得できますchpasswd

{  printf "%s:" "$username";
   head /dev/urandom | tr -dc A-Za-z0-9 | head -c 13 ; echo ''
} | chpasswd 

を1回実行するだけで複数のパスワードを変更する場合chpasswdは、重要な部分を簡単に繰り返してください。または、関数にします:

genpws() {
    for user in "$@"; do
        printf "%s:" "$user";
        head /dev/urandom | tr -dc A-Za-z0-9 | head -c 13
        echo
    done
}
genpws username1 username2... | chpasswd 

余談ですhead /dev/urandomが、urandomライン指向ではないので少し奇妙に感じます。そこから過剰な量のバイトを読み取る可能性があり、これは利用可能なエントロピーのカーネルの概念に影響を与え、その結果、/dev/randomブロックにつながる可能性があります。一定量のデータを読み取るだけでbase64、ランダムなバイトを印刷可能な文字に変換するなどの方法を使用すると(得られるバイトの約3/4を捨てるのではなく)よりクリーンになります。

このようなものはあなたに約を与えるでしょう。16文字と数字:

head -c 12 /dev/urandom | base64 | tr -dc A-Za-z0-9 

(それは、16以下の量であり、+かつ/、文字の出力にbase64少なくとも14個の文字を残しての99%の確率で約与えることを、私は右の私の組合せ論を得た場合のいずれかのチャンスはそう、文字ごとに1/32である。、および99.99%の確率で少なくとも12を離れる。)


あなたのprintf複数のユーザ名に複数行を返すが、私は上のあなたの発言を感謝:ソリューションは、私の元のコードが何を行っていないhead urandom
ニルス・ヴェルナー

@NilsWerner、まあ、私は複数のユーザーへの拡張は明らかですが。しかし、関係なく、一度に複数のユーザーのユーザー名とパスワードのペアを生成する関数を作成できます。(編集を参照)
ilkkachu

3
必要な文字を十分に含むurandomの最初の10個の「行」に依存することはできません。代わりに、trを介してurandomを直接実行するだけです。
クサラナナンダ

@Kusalananda、私のhead -c 10 | base64パイプラインhead | trですか、それともニルスのパイプラインですか?かかわらず、ランダムバイトの10「行」は、非常に可能性が高い(のみ1 256には、改行であろうと与えられた)数百バイトになることです理論、それは正確に10バイトかもしれないが、確率は完全に無視することができます。同様に、を使用するときにbase64、ランダムバイトがたまたまジャスト\xffである場合、base64は単なるスラッシュの文字列になりますが、それもほとんどありません。気になる場合は、10バイト以上を読み取って、そのオッズを減らし、結果の出力の長さを削減できます。
-ilkkachu

1
@ilkkachu両方のコードを参照しています。ランダムなバイトを読み取り、不要なものを除外した後に特定の長さのものが必要な場合は、必要なものが確実に得られるまでデータソースを切断しないでください。あなたが言うように、それは非常だそうあなたがから10改行の文字列を取得したいということ/dev/urandomが、リスクは0%ではありません。
クサラナナンダ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.