Menghasilkan kata sandi acak; mengapa ini tidak portabel?


21

Saya ingin membuat kata sandi acak, dan saya melakukannya seperti ini:

</dev/urandom tr -dc [:print:] | head -c 64

Di laptop saya, yang menjalankan Ubuntu, ini hanya menghasilkan karakter yang dapat dicetak, sebagaimana dimaksud. Tetapi ketika saya ssh ke server sekolah saya, yang menjalankan Red Hat Enterprise Linux, dan menjalankannya di sana, saya mendapatkan output seperti 3!ri�b�GrӴ��1�H�<�oM����&�nMC[�Pb�|L%MP�����9��fL2q���IFmsd|l�K, yang tidak akan berhasil sama sekali. Apa yang salah di sini?

Jawaban:


34

Ini masalah lokal dan tr Anda .

Saat ini, GNU tr sepenuhnya hanya mendukung karakter byte tunggal. Jadi di lokal menggunakan pengkodean multibyte, hasilnya bisa aneh:

$ </dev/urandom LC_ALL=vi_VN.tcvn tr -dc '[:print:]' | head -c 64
`�pv���Z����c�ox"�O���%�YR��F�>��췔��ovȪ������^,<H ���>

Shell akan mencetak karakter multi-byte dengan benar, tetapi GNU trakan menghapus byte yang menurutnya tidak dapat dicetak.

Jika Anda ingin itu stabil, Anda harus mengatur lokal:

$ </dev/urandom LC_ALL=C tr -dc '[:print:]' | head -c 64
RSmuiFH+537z+iY4ySz`{Pv6mJg::RB;/-2^{QnKkImpGuMSq92D(6N8QF?Y9Co@

14
1 karena ini membuat saya sadar (setelah menggunakan shell di Unix / Linux hanya sekitar 30 tahun), bahwa pengalihan stdin / stdout / stderr tidak harus diposisikan setelah perintah itu berlaku.
Anthon

Hanya komentar, jika beberapa lokal aneh diatur, bukankah shell masih dapat mencetak karakter dengan benar, bahkan jika mereka tidak ascii? Setidaknya shell yang kompeten (tidak termasuk xterm tentu saja)?
orion

2
@orion: shell akan mencetak karakter dengan benar. Dalam hal ini, itu masalah utama. Itu dihapus byte yang menurutnya tidak dapat dicetak, membuat hasilnya aneh.
cuonglm

@orion Aliran byte acak yang seragam tidak, pada umumnya, akan menjadi aliran acak seragam dari pengkodean karakter UTF-8 yang terbentuk dengan baik .
zwol

Selain itu, kecuali jika Anda memiliki spasi pada kata sandi, Anda harus menggunakan :graph:alih-alih :print::</dev/urandom LC_ALL=C tr -dc '[:graph:]' | head -c 64
edan

11

Pertimbangkan saja

$ dd if=/dev/urandom bs=48 count=1 status=none | base64
imW/X60Sk9TQzl+mdS5PL7sfMy9k/qFBWWkzZjbYJttREsYpzIguWr/uRIhyisR7

Ini memiliki dua keunggulan:

  • Anda hanya membaca 48 byte dari perangkat acak, bukan ~ 8KB; jika proses lain pada host yang sama membutuhkan angka acak, 8KB yang dikuras sekaligus bisa menjadi masalah serius. (Ya, bisa dibilang tidak ada yang harus menggunakan perangkat acak pemblokiran , tetapi orang - orang melakukannya .)

  • Keluaran base64hampir tidak mengandung karakter dengan makna khusus. (Untuk tidak sama sekali, taktik | tr +/ -_pada akhirnya, dan (seperti pada contoh) memastikan jumlah byte masukan untuk base64merupakan kelipatan dari 3.)

Kata sandi yang dihasilkan dengan cara ini memiliki tepat 384 bit entropi, yang agak kurang dari apa yang Anda lakukan (log 2 96 64 ≈ 421,4), tetapi lebih dari cukup untuk sebagian besar tujuan (256 bit entropi aman dalam "masih menebak ketika" Wilayah "Matahari terbakar habis" kecuali untuk kunci RSA, AFAIK).


3

Orang lain sudah menunjukkan bahwa lokal menentukan apa [:print:]artinya. Namun, tidak semua karakter yang dapat dicetak cocok untuk kata sandi (bahkan dalam ascii). Anda benar-benar tidak ingin spasi, tab, dan # $% ^? di kata sandi Anda - itu tidak hanya sulit untuk diingat, itu juga berpotensi berbahaya bagi sistem otentikasi yang mendasarinya, mungkin tidak mungkin untuk masuk dalam bidang input, dan sebagainya. Dalam hal ini, Anda harus memilih karakter "waras" secara manual:

LC_ALL=C </dev/urandom tr -dc '[:alnum:]_' | head -c 64

atau sederhana

</dev/urandom tr -dc 'A-Za-z0-9_' | head -c 64

Atau bahkan lebih baik, gunakan base64seperti yang disarankan dalam jawaban lain.


Kata sandi yang dimaksud tidak akan pernah dimasukkan oleh manusia (jika saya akan menggunakan Diceware saja) dan saya cukup yakin bahwa sistem yang mendasarinya dapat menangani karakter khusus tanpa masalah. Bagaimanapun, terima kasih.
Taymon

4
Apa yang Anda katakan benar-benar salah. Memaksa pengguna untuk hanya menggunakan huruf ascii, angka dan garis bawah mengurangi ukuran alfabet, membuat jauh lebih mudah untuk memecahkan kata sandi bagi penyerang. Sistem otentikasi yang bahkan tidak dapat menangani ?atau ^terlalu buruk untuk dianggap serius.
Bakuriu

2
Jika sistem auth atau bidang input Anda tersumbat pada simbol ASCII biasa ... maka Anda melakukan sesuatu yang salah dan tidak dapat dipercaya dengan informasi pribadi saya. Sama sekali tidak ada alasan untuk tidak menerima semua karakter (termasuk spasi) di kata sandi Anda.
nzifnab

2
Tampaknya ini bukan masalahnya di sini, tetapi ketika menyangkut input manusia, jauh lebih mudah untuk mengingat kata sandi alfanumerik panjang yang menyimpan makna unik bagi pemilik daripada kumpulan simbol yang lebih pendek. Ada juga masalah memasukkan karakter-karakter ini di berbagai keyboard (tidak semua orang memiliki ^ pada tingkat pertama dan kebanyakan orang bahkan tidak tahu di mana atau apa backtick itu), kotak input hampir pasti tidak dapat menangani karakter tab, dan Jumlah situs web yang mengejutkan di luar sana masih rentan terhadap kesalahan validasi, injeksi sql, atau bahkan sensitivitas kasus yang tidak pasti.
orion

1
Hanya sebuah catatan: di C locale [:print:]class tidak termasuk tab. Ini hanya [:alnum:]+ [:punct:]+ ruang (ruang tunggal, bukan [:space:] ).
jimmij

2

Bagaimana dengan

tr -dc [:print:] < /dev/urandom | head -c 64 | strings

string harus mencetak output urandom dalam format yang dapat dicetak


Ini memberi-bash: /dev/urandom: Permission denied
Anthon

maaf lupa kucing terkemuka
Blindstealer

2

Saya tidak tahu apakah ada alasan mengapa Anda menggunakan /dev/randomuntuk menghasilkan kata sandi, tapi saya akan merekomendasikan Anda menggunakan pwgen untuk mengurangi rasa sakit Anda.

$ pwgen -s 10 1

Di mana 10 adalah panjang kata sandi.

http://man.cx/pwgen


1
#Chars allowed in password (I don't like l,o,O, etc):
P="0123456789ABCDEFGHIJKLMNPQRSTUVWXYZabcdefghijkmnpqrstuvwxyz"

#Or such:
#P="a-zA-Z0-9"

head -c 8 < /dev/urandom | tr '\000-\377' "$P$P$P$P$P"
echo

Metode ini IMHO lebih pintar ketika mengkonsumsi data dari / dev / urandom String yang disisipkan sebagai $ P $ P $ P ... harus memiliki setidaknya 256 karakter.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.