Apakah ada cara untuk melewatkan data sensitif di bash menggunakan prompt, untuk perintah apa pun?

40

Misalkan saya menggunakan sha1passuntuk menghasilkan hash dari beberapa kata sandi sensitif pada baris perintah. Saya dapat menggunakan sha1pass mysecretuntuk menghasilkan hash mysecrettetapi ini memiliki kelemahan yang mysecretsekarang dalam sejarah bash. Apakah ada cara untuk mencapai tujuan akhir dari perintah ini sambil menghindari pengungkapan mysecretdalam teks biasa, mungkin dengan menggunakan passwdprompt-style?

Saya juga tertarik dengan cara umum untuk melakukan ini untuk meneruskan data sensitif ke perintah apa pun. Metode akan berubah ketika data sensitif dilewatkan sebagai argumen (seperti dalam sha1pass) atau pada STDIN ke beberapa perintah.

Apakah ada cara untuk menyelesaikan ini?


Sunting : Pertanyaan ini menarik banyak perhatian dan ada beberapa jawaban bagus yang ditawarkan di bawah ini. Ringkasan adalah:

  • Sesuai jawaban Kusalananda , idealnya seseorang tidak perlu memberikan kata sandi atau rahasia sebagai argumen baris perintah ke utilitas. Ini rentan dalam beberapa cara seperti yang dijelaskan olehnya, dan seseorang harus menggunakan utilitas yang dirancang lebih baik yang mampu mengambil input rahasia pada STDIN
  • Jawaban @ vfbsilva menjelaskan cara mencegah hal-hal agar tidak disimpan dalam bash history
  • @Jawab Jonathan menjelaskan metode yang sangat baik untuk mencapai ini selama program dapat mengambil data rahasianya pada STDIN. Karena itu, saya telah memutuskan untuk menerima jawaban ini. sha1passdi OP saya hanya sebuah contoh, tetapi diskusi telah menetapkan bahwa ada alat yang lebih baik yang mengambil data pada STDIN.
  • seperti @R .. mencatat dalam jawabannya , penggunaan ekspansi perintah pada variabel tidak aman.

Jadi, secara ringkas, saya telah menerima jawaban @ Jonathan karena ini adalah solusi terbaik mengingat Anda memiliki program yang dirancang dengan baik dan berperilaku baik. Meskipun melewatkan kata sandi atau rahasia sebagai argumen baris perintah pada dasarnya tidak aman, jawaban lain menyediakan cara untuk mengurangi masalah keamanan yang sederhana.

mencemari
sumber
6
Tidak hanya itu: Siapa saja di mesin yang sama dengan izin untuk mendaftar proses yang berjalan berpotensi dapat melihat yang sha1pass mysecretsedang berjalan, dan karenanya tahu apa mysecretitu. (Ini hanya bekerja selama beberapa detik saat program ini benar-benar berjalan, tentu saja ...)
MathematicalOrchid
@MathematicalOrchid Ini bisa dihindari dengan menjalankan di mesin virtual pribadi. Tapi itu mungkin terlalu banyak pekerjaan untuk diatur untuk menghasilkan hanya satu kata sandi ... :-)
Kusalananda
5
@ Kusalananda Maksud saya adalah lebih "jangan pernah memasukkan data sensitif pada baris perintah, bahkan jika Anda mencari cara untuk mematikan sejarah perintah" ...
MathematicalOrchid
2
Asal tahu saja, SHA-1 sudah tidak digunakan lagi untuk hash kunci atau kata sandi sejak beberapa tahun sekarang.
David Foerster
2
Perhatikan bahwa jika sistem menjalankan daemon audit, semua perintah dan semua argumen oleh semua pengguna dicatat secara terpusat oleh root, sehingga siapa pun yang dapat mengakses log tersebut akan melihat ini.
Randall

Jawaban:

21

Jika menggunakan shell zshatau bash, gunakan opsi -s ke readshell builtin untuk membaca garis dari perangkat terminal tanpa itu menggemakannya.

IFS= read -rs VARIABLE < /dev/tty

Kemudian Anda dapat menggunakan beberapa pengalihan mewah untuk menggunakan variabel sebagai stdin.

sha1pass <<<"$VARIABLE"

Jika ada yang menjalankan ps, yang akan mereka lihat adalah "sha1pass".

Itu mengasumsikan bahwa sha1passmembaca kata sandi dari stdin (pada satu baris, mengabaikan pembatas baris) ketika tidak diberi argumen.

Jonathan
sumber
Saya percaya bahwa kami menetapkan bahwa sha1passtidak menggunakan aliran input standar.
Kusalananda
@ Kusalananda Oke, tetapi metode ini akan bekerja untuk program yang membaca dari stdin.
Jonathan
Jadi, dengan asumsi utilitas dapat mengambil input rahasianya pada STDIN, ini adalah solusi yang sehat dan aman, dari sisi keamanan?
Kuburkan
Saya telah memutuskan untuk menerima jawaban ini, mengingat itu adalah solusi terbaik mengingat Anda memiliki program yang dirancang dengan baik untuk bekerja dengannya. sha1passhanyalah contoh di OP saya, dan jelas bukan pilihan terbaik untuk digunakan untuk ini.
Kuburkan
1
@emulasikan, ... tidak aman di baris perintah . Dalam konteks heredoc atau herestring (seperti dalam jawaban di sini), itu tidak terkena ps, tetapi dapat ditulis ke file sementara - jika seseorang ingin menghindari itu, maka sshpass < <(printf '%s\n' "$VARIABLE")dapat dipertimbangkan (karena printfmerupakan bawaan, bukan perintah eksternal, itu tidak diteruskan ke execvdan dapat diakses melalui ps).
Charles Duffy
36

Idealnya, Anda tidak pernah mengetikkan kata sandi teks-jelas pada baris perintah sebagai argumen ke perintah. Melakukannya menjadikan kata sandi argumen untuk perintah, dan argumen baris perintah dapat dilihat dalam tabel proses dengan menggunakan alat sederhana seperti psatau masuk ke beberapa log audit.

Karena itu, pasti ada cara untuk menyembunyikan kata sandi yang sebenarnya dari sejarah perintah shell.

sha1pass "$( head -n 1 )"

Kemudian ketikkan kata sandi dan tekan Enter. The headperintah yang digunakan di sini menerima tepat satu garis masukan dan baris baru terakhir yang Anda ketik tidak akan menjadi bagian dari data yang dilewatkan ke sha1pass.

Untuk mencegah karakter bergema:

sha1pass "$( stty -echo; head -n 1; stty echo )"

The stty -echoperintah bergantian off bergema dari karakter diketik di terminal. Gema kemudian dipulihkan dengan stty echo.

Untuk meneruskan input standar, perintah terakhir itu dapat diubah (Anda akan melakukan ini jika sha1passdata yang diterima pada input standar, tetapi tampak seolah-olah utilitas khusus ini mengabaikan input standarnya):

{ stty -echo; head -n 1; stty echo; } | somecommand

Jika Anda memerlukan input multi-baris (di atas mengasumsikan satu baris harus dilewati, tanpa karakter baris baru di akhir), lalu ganti seluruh headperintah dengan catdan hentikan input (dengan asumsi somecommanditu sendiri berbunyi hingga akhir file) dengan Ctrl+D( mengikuti Returnjika Anda ingin memasukkan karakter baris baru dalam input, atau dua kali jika tidak).

Ini akan berfungsi terlepas dari shell apa yang Anda gunakan (asalkan itu shell Bourne-like atau rc-like).

Beberapa shell mungkin dibuat untuk tidak menyimpan perintah yang diketik dalam file histori mereka jika perintah tersebut didahului oleh spasi. Ini biasanya melibatkan harus mengatur HISTCONTROLke nilai ignorespace. Ini didukung oleh setidaknya bashdan kshpada OpenBSD, tetapi tidak oleh eg ksh93atau dash. zshpengguna dapat menggunakan histignorespaceopsi atau HISTORY_IGNOREvariabel mereka untuk menentukan pola untuk diabaikan.

Dalam cangkang yang mendukung membaca dengan readtanpa menggema karakter ke terminal, Anda juga dapat menggunakan

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"

tetapi ini jelas masih memiliki masalah yang sama dengan berpotensi mengungkapkan kata sandi dalam tabel proses.

Jika utilitas membaca dari input standar, dan jika shell mendukung "di sini-string", yang di atas dapat diubah menjadi

IFS= read -rs password
somecommand <<<"$password"

Ringkasan komentar di bawah ini:

  • Menjalankan perintah dengan kata sandi yang diberikan pada baris perintah, yang dilakukan oleh semua perintah di atas, kecuali yang mengirim data ke perintah, berpotensi akan membuat kata sandi terlihat oleh siapa saja yang menjalankan pspada saat yang sama. Namun tidak satu pun dari perintah di atas yang akan menyimpan kata sandi yang diketikkan dalam file histori shell jika dijalankan dari shell interaktif.

  • Program berperilaku baik yang membaca kata sandi teks jernih melakukannya dengan membaca dari input standar mereka, dari file, atau langsung dari terminal.

  • sha1pass memang membutuhkan kata sandi pada baris perintah, baik diketik langsung atau menggunakan beberapa bentuk substitusi perintah.

  • Jika memungkinkan, gunakan alat lain.

Kusalananda
sumber
11
Ini salah. Hasil ekspansi perintah $(...)akan menjadi bagian dari baris perintah dan terlihat dalam psoutput kecuali pada sistem dengan hardened / proc.
R ..
3
@ Kusalananda, bahkan menimpa argumen setelah Anda mulai meninggalkan jendela yang rentan sebelum menimpa terjadi; itu mitigasi, bukan perbaikan.
Charles Duffy
5
@ Kusalananda, tidak ada program yang dirancang dengan baik untuk hashing password akan memerlukan input pada baris perintah, sehingga kondisional pada dasarnya diberikan - jika tidak , seseorang harus memilih alat yang berbeda.
Charles Duffy
4
@CharlesDuffy: Alat di sini tampaknya rusak secara fundamental. sha1passberjalan tanpa kata sandi pada baris perintah tampaknya menghasilkan output tanpa membaca apa pun ... Jadi OP perlu memilih alat yang berbeda.
R ..
8
Jawaban ini tidak aman dari perspektif keamanan, dan satu-satunya keuntungan adalah bahwa kata sandi tidak muncul dalam riwayat shell, tetapi keuntungan itu lebih mudah dicapai dengan memasukkan spasi di depan perintah
Ferrybig
25

Jika Anda mengatur HISTCONTROLseperti itu:

HISTCONTROL=ignorespace

dan mulai perintah dengan spasi:

~$  mycommand

itu tidak akan disimpan dalam sejarah.

vfbsilva
sumber
10

Lulus data sensitif melalui pipa atau di sini-dok:

command_with_secret_output | command_with_secret_input

atau:

command_with_secret_input <<EOF
$secret
EOF

Tidak masalah jika rahasia berada dalam variabel shell (tidak diekspor), tetapi Anda tidak akan pernah bisa menggunakan variabel itu di baris perintah, hanya di sini-dokumen dan internal shell.

Seperti dicatat oleh Kusalananda dalam komentar, jika Anda memasukkan perintah dalam shell interaktif, baris yang Anda masukkan untuk dokumen di sini akan disimpan dalam histori shell, jadi tidak aman untuk mengetikkan kata sandi di sana, tetapi harus tetap aman untuk menggunakan variabel shell yang berisi rahasia; sejarah akan berisi teks $secretdaripada apa pun yang $secretdiperluas.

Penggunaan ekspansi perintah tidak aman :

command_with_secret_input "$(command_with_secret_output)"

karena output akan dimasukkan pada baris perintah dan terlihat di psoutput (atau secara manual membaca dari / proc) kecuali pada sistem dengan hardened / proc.

Penugasan ke sebuah variabel juga oke:

secret=$(command_with_secret_output)
R ..
sumber
Apa yang saya cari adalah perintah aktual command_with_secret_outputyang memungkinkan saya mengetik keluaran rahasia. Apakah ada perintah seperti itu yang bisa diganti di sini?
Kuburkan
Perhatikan bahwa mengetik dokumen di sini dalam bash sesi interaktif akan menyimpan dokumen dalam file riwayat.
Kusalananda
@cemulate: Cukup gunakan shell builtin read, mis read -r secret. Lalu rahasiamu ada di $secret. Anda dapat menjalankan stty sebelum / sesudahnya untuk menyembunyikan input jika Anda mau.
R ..
3
@ Kusalananda: sha1passtampaknya rusak / tidak dapat digunakan / tidak aman karena tidak dapat membaca kata sandi dari stdin atau file. Utilitas yang berbeda diperlukan untuk menyelesaikan masalah, saya pikir.
R ..
1
@cemulate Komentar terakhir Anda ke R ada di tempat. Itu sebabnya itu tidak akan membantu. read -rsakan melakukan pekerjaan itu (jika Anda termasuk -runtuk dapat memiliki kata sandi dengan garis miring terbalik di dalamnya), tetapi kemudian Anda kembali berpotensi memamerkan kata sandi dalam daftar proses (dan tergantung pada apakah proses akuntansi diaktifkan dan bagaimana hal itu dikonfigurasi , dalam proses log akuntansi juga).
Kusalananda
6

Cukup tulis nilai ke dalam file dan berikan file:

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

Saya tidak yakin cara sha1passkerjanya, jika bisa mengambil file sebagai input, Anda bisa menggunakan sha1pass < mysecret. Jika tidak, menggunakan catmungkin menjadi masalah karena termasuk baris baru akhir. Jika itu masalahnya, gunakan (jika headdukungan Anda -c):

head -c-1 mysecret | sha1pass 
terdon
sumber
2
Mengapa menulis kata sandi ke disk pada contoh pertama Anda saat Anda bisa melakukannya cat | sha1pass? cat mysecret | sha1passdan sha1pass < mysecretmemiliki perilaku yang sama sehubungan dengan baris baru akhir. cattidak menambahkan baris baru. Lagi pula, jika sha1passmendukung lewat kata sandi melalui input standar, saya akan berharap untuk mengabaikan baris baru final dengan sendirinya. File dengan baris yang tidak diakhiri oleh baris baru tidak wajar di unix, jadi akan aneh untuk mengharapkan file yang tidak diakhiri oleh baris baru.
JoL
@ JoL i) karena saya tidak memikirkan itu: / Tapi bagaimana cara kerjanya? cat | sha1passtampaknya berjalan sha1passsebelum memberi saya kesempatan untuk memasukkan input apa pun. ii) Tidak, tentu saja cat mysecrettidak menambahkan baris baru, saya tidak pernah mengatakan catmenambahkannya, hanya itu termasuk itu.
terdon
Begitu, tapi itu tidak seperti < mysecretmenghapusnya juga. :)
JoL
Sudahlah. Sekarang saya membaca kembali, saya melihat bahwa Anda mengatakan itu untuk kemudian melamar head -c-1. Saya kira saya baru saja bingung mengapa menggunakan cat mysecret | sha1passdan kemudian mengusulkan sha1pass < mysecret. Saya kira khawatir adalah sha1pass mungkin mengeluh tentang file biasa untuk stdin; Saya tidak yakin mengapa.
JoL
@ JoL itu lebih karena saya tidak pernah menggunakan sha1passdan tidak dapat menemukan manual atau -hatau bentuk dokumentasi lainnya dalam beberapa menit saya menghabiskan pencarian dan jadi tidak tahu apakah berjalan sha1pass foodiperlakukan foosebagai string input atau sebagai file input . Karena itu saya memberikan opsi untuk menangani setiap kemungkinan.
terdon
1

Jika apa yang dilakukan terdon adalah mungkin, maka itu solusi terbaik, melewati input standar. Satu-satunya masalah yang tersisa adalah dia menulis kata sandi ke disk. Kita bisa melakukan ini sebagai gantinya:

stty -echo
echo -n "password: "
head -1 | sha1pass
stty echo

Seperti yang dikatakan Kusalananda, stty -echopastikan apa yang Anda ketik tidak terlihat sampai Anda melakukannya stty echolagi. head -1akan mendapatkan satu baris dari input standar dan meneruskannya ke sha1pass.

JoL
sumber
0

Saya akan menggunakan

sha1pass "$(cat)"

catakan membaca dari stdin hingga EOF, yang dapat disebabkan oleh menekan Ctrl + D. Kemudian, hasilnya akan diteruskan sebagai argumen untuksha1pass

oktupol
sumber
3
Jawaban R .. menjelaskan mengapa ini tidak aman.
hvd