Apakah aman menggunakan gema untuk meneruskan data sensitif ke chpasswd?

17

Saya mencoba mengatur beberapa kata sandi akun pengguna secara massal chpasswd. Kata sandi harus dibuat secara acak dan dicetak stdout(saya harus menuliskannya atau menyimpannya di penyimpanan kata sandi), dan juga diteruskan chpasswd.

Dengan naif, saya akan melakukan ini seperti ini

{
  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)

Namun saya khawatir tentang meneruskan kata sandi baru sebagai argumen baris perintah echo, karena argumen biasanya terlihat oleh pengguna lain di ps -aux(meskipun saya tidak pernah melihat echobaris apa pun muncul di ps).

Apakah ada cara alternatif untuk menambahkan nilai ke kata sandi saya yang dikembalikan, dan kemudian meneruskannya chpasswd?

Nils Werner
sumber
6
echoadalah shell built-in. Itu tidak akan muncul di tabel proses.
Kusalananda

Jawaban:

15

Kode Anda harus aman karena echotidak akan muncul di tabel proses karena ini merupakan built-in shell.

Inilah solusi alternatif:

#!/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

Ini menciptakan nama dan kata sandi siswa Anda n, tanpa menggunakan kata sandi apa pun di baris perintah apa pun dari perintah apa pun.

The pasteutilitas lem bersama-sama beberapa file sebagai kolom dan sisipan pembatas di antara mereka. Di sini, kami menggunakan :sebagai pembatas dan memberinya dua "file" (proses substitusi). Yang pertama berisi output dari seqperintah yang menciptakan 20 nama pengguna siswa, dan yang kedua berisi output dari pipa yang menciptakan 20 string acak dengan panjang 13.

Jika Anda memiliki file dengan nama pengguna yang telah dibuat:

#!/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

Ini akan menyimpan kata sandi dan nama pengguna ke file secret.txtalih-alih menunjukkan kata sandi yang dihasilkan di terminal.

Kusalananda
sumber
2
Itu solusi cerdas yang tidak perlu echoatau printf, namun kodenya agak canggung untuk diuraikan
Nils Werner
@NilsWerner Menambahkan sedikit penjelasan. Beritahu saya jika ada hal tertentu yang Anda ingin saya kembangkan.
Kusalananda
1
Anda seharusnya tidak mengandalkan echomenjadi builtin shell. Pada kebanyakan kerang, tapi sama sekali tidak ada persyaratan bahwa itu adalah.
Austin Hemmelgarn
1
@ Kusalananda Hanya ingin tahu, apakah ada perbedaan efektif antara tee secret.txt > >(chpasswd)dan tee secret.txt | chpasswd? Yang terakhir ini tampaknya jauh lebih umum, jadi saya bertanya-tanya mengapa Anda memilih untuk menggunakan proses substitusi alih-alih pipa biasa
Christopher Shroba
1
@ChristopherShroba Tidak ada alasan selain itu mirip dengan kode yang sudah ada dalam pertanyaan (menggunakan proses substitusi dengan tee). Sekarang setelah Anda menunjukkannya, saya pikir saya akan benar-benar mengubahnya (terlihat lebih baik). Terima kasih.
Kusalananda
8

echosangat mungkin dibangun ke dalam shell, sehingga tidak akan muncul pssebagai proses terpisah.

Tetapi Anda tidak perlu menggunakan substitusi perintah, Anda hanya dapat memiliki output dari pipa langsung ke chpasswd:

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

Jika Anda ingin mengubah beberapa kata sandi dengan sekali jalankan chpasswd, seharusnya mudah untuk mengulangi bagian-bagian penting. Atau membuatnya menjadi fungsi:

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 

Sebagai tambahan: itu head /dev/urandomterasa agak aneh karena urandomtidak berorientasi garis. Mungkin membaca jumlah byte yang berlebihan dari itu, yang akan mempengaruhi gagasan kernel tentang entropi yang tersedia, yang pada gilirannya dapat menyebabkan /dev/randompemblokiran. Mungkin lebih bersih untuk hanya membaca jumlah data yang tetap, dan menggunakan sesuatu seperti base64untuk mengkonversi byte acak ke karakter yang dapat dicetak (bukan hanya membuang sekitar 3/4 byte yang Anda dapatkan).

Sesuatu seperti ini akan memberi Anda sekitar. 16 karakter dan angka:

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

(Yaitu, 16 lebih sedikit dari jumlah +dan /karakter dalam output dari base64. Peluang dari keduanya adalah 1/32 per karakter, jadi jika saya benar kombinatorik saya, yang memberikan sekitar 99% kemungkinan meninggalkan setidaknya 14 karakter, dan kemungkinan 99,99% meninggalkan setidaknya 12.)

ilkkachu
sumber
Anda printfsolusi tidak melakukan apa kode asli saya tidak: kembali beberapa baris untuk beberapa username, tapi saya menghargai komentar Anda padahead urandom
Nils Werner
@ NilsWerner, well, saya pikir ekspansi ke banyak pengguna jelas. Namun tidak masalah, kami dapat membuat fungsi untuk menghasilkan nama pengguna: pasangan kata sandi untuk beberapa pengguna sekaligus. (lihat edit)
ilkkachu
3
Anda tidak dapat benar-benar mengandalkan 10 "garis" pertama dari urandom yang mengandung cukup banyak karakter yang Anda inginkan. Jalankan saja urandom langsung melalui tr.
Kusalananda
@ Kusalananda, maksud Anda head -c 10 | base64pipeline saya , atau yang Nils dengan head | tr? 10 "baris" byte acak sangat mungkin ratusan byte (mengingat bahwa hanya 1 dari 256 yang akan menjadi baris baru), meskipun secara teori mungkin tepat 10 byte, tetapi kemungkinan itu benar-benar dapat diabaikan. Demikian pula ketika menggunakan base64, jika byte acak kebetulan saja \xff, maka base64 akan menjadi hanya serangkaian garis miring, tapi itu juga tidak mungkin. Jika Anda peduli, Anda dapat membaca lebih dari 10 byte, yang mengurangi peluang itu, dan kemudian memotong panjang output yang dihasilkan.
ilkkachu
1
@ilkkachu saya mengacu pada kedua kode. Jika Anda membaca byte acak, dan menginginkan sesuatu yang panjang tertentu setelah menyaring apa yang tidak Anda inginkan, maka jangan memotong sumber data sampai Anda yakin bahwa Anda mendapatkan apa yang Anda butuhkan. Seperti yang Anda katakan, sangat tidak mungkin Anda akan mendapatkan untaian sepuluh baris baru /dev/urandom, tetapi risikonya bukan 0%.
Kusalananda