Bagaimana cara mengirimkan kata sandi ke proses anak?

18

Melewati kata sandi pada baris perintah (ke proses anak dimulai dari program saya) diketahui tidak aman (karena dapat dilihat bahkan oleh pengguna lain dengan perintah ps). Apakah boleh untuk meneruskannya sebagai variabel lingkungan?

Apa lagi yang bisa saya gunakan untuk melewatinya? (Kecuali variabel lingkungan) solusi termudah tampaknya menggunakan pipa, tetapi solusi termudah ini tidak mudah.

Saya memprogram di Perl.

porton
sumber
2
Mengapa itu tidak mudah? Itu tidak harus menjadi pipa yang terpisah / bernama, hanya stdin / out biasa akan melakukan ... yang seharusnya tidak terlalu banyak masalah dalam bahasa apa pun. Anda dapat meletakkannya di file konfigurasi biasa jika Anda dapat memastikan itu hanya dapat dibaca oleh proses yang menarik (yang jauh lebih sulit daripada kedengarannya).
frostschutz
1
Jika Anda tidak memanggil eksekutif pada anak Anda masih memiliki salinan kata sandi tanpa perlu melakukan apa pun.
James Youngman

Jawaban:

26

Argumen proses terlihat oleh semua pengguna, tetapi lingkungan hanya dapat dilihat oleh pengguna yang sama ( setidaknya di Linux , dan saya pikir pada setiap varian unix modern). Jadi mengirimkan kata sandi melalui variabel lingkungan adalah aman. Jika seseorang dapat membaca variabel lingkungan Anda, mereka dapat menjalankan proses seperti Anda, jadi itu sudah berakhir.

Konten lingkungan berisiko berisiko bocor secara tidak langsung, misalnya jika Anda menjalankan psuntuk menyelidiki sesuatu dan secara tidak sengaja menyalin-menempelkan hasilnya termasuk variabel lingkungan rahasia di tempat umum. Risiko lain adalah bahwa Anda meneruskan variabel lingkungan ke program yang tidak memerlukannya (termasuk anak-anak dari proses yang membutuhkan kata sandi) dan program itu memaparkan variabel lingkungannya karena tidak mengharapkannya dirahasiakan. Seberapa buruk risiko kebocoran sekunder ini tergantung pada apa proses dengan kata sandi itu (berapa lama itu berjalan? Apakah itu menjalankan subproses?).

Lebih mudah untuk memastikan bahwa kata sandi tidak akan bocor secara tidak sengaja dengan melewatkannya melalui saluran yang tidak dirancang untuk dikuping, seperti pipa. Ini cukup mudah dilakukan di sisi pengirim. Misalnya, jika Anda memiliki kata sandi dalam variabel shell, Anda bisa melakukannya

echo "$password" | theprogram

jika theprogrammengharapkan kata sandi pada input standarnya. Perhatikan bahwa ini aman karena echomerupakan builtin; itu tidak akan aman dengan perintah eksternal karena argumen akan diekspos dalam psoutput. Cara lain untuk mencapai efek yang sama adalah dengan dokumen di sini:

theprogram <<EOF
$password
EOF

Beberapa program yang memerlukan kata sandi dapat diperintahkan untuk membacanya dari deskriptor file tertentu. Anda dapat menggunakan deskriptor file selain dari input standar jika Anda membutuhkan input standar untuk hal lain. Misalnya dengan gpg:

get-encrypted-data | gpg --passphrase-fd 3 --decrypt … 3<<EOP >decrypted-data
$password
EOP

Jika program tidak bisa disuruh membaca dari deskriptor file tetapi bisa disuruh baca dari file, Anda bisa menyuruhnya membaca dari deskriptor file dengan menggunakan nama file seperti `/ dev / fd / 3.

theprogram --password-from-file=/dev/fd/3 3<<EOF
$password
EOF

Di ksh, bash atau zsh, Anda bisa melakukan ini dengan lebih ringkas melalui proses substitusi.

theprogram --password-from-file=<(echo "$password")
Gilles 'SANGAT berhenti menjadi jahat'
sumber
Pada Solaris 9 dan yang lebih lama, /usr/ucb/psadalah setuid root sehingga dapat membaca dan menampilkan variabel lingkungan dari proses lain - ini dihapus dalam Solaris 10, jadi jawaban "setiap varian Unix modern lainnya" di atas berlaku untuk rilis Solaris mulai 2005 & yang lebih baru.
alanc
@alanc Memang, saya tidak menganggap Solaris <10 sebagai modern saat ini. Solaris 9 hampir setua Windows XP!
Gilles 'SO- berhenti bersikap jahat'
Gilles: ada hari-hari saya mengalami kesulitan mempertimbangkan Solaris 10 modern sekarang karena Solaris 11 sudah lebih dari 5 tahun, jadi saya benar-benar mengerti dan setuju, tetapi sayangnya tahu beberapa orang masih menjalankan Solaris 8 atau 9.
alanc
10

Alih-alih menyampaikan kata sandi secara langsung melalui argumen atau variabel lingkungan

#!/bin/bash
#filename: passwd_receiver
echo "The password is: $1"

gunakan argumen atau variabel lingkungan yang sama untuk meneruskan nama file :

#!/bin/bash
#filename: passwd_receiver
echo "The password is: $(< "$1")"

Kemudian Anda dapat melewati baik izin yang dilindungi file biasa (meskipun itu tidak akan melindungi Anda dari proses lain yang berjalan di bawah pengguna yang sama), atau /dev/stdindan pipa di (yang AFAIK akan melindungi Anda dari proses lain yang berjalan di bawah pengguna yang sama):

 echo PASSWORD | ./passwd_receiver /dev/stdin 

Jika Anda menggunakan di /dev/stdinsini, sangat penting bahwa itu adalah pipa . Jika terminal, itu akan dapat dibaca oleh proses lain yang berjalan di bawah pengguna yang sama.

Jika Anda sudah perlu menggunakan Anda /dev/stdinuntuk sesuatu yang lain, Anda bisa menggunakan subtitusi proses jika Anda menggunakan shell yang mendukungnya, yang pada dasarnya setara dengan menggunakan pipa:

./passwd_receiver <(echo PASSWORD)

Named pipes (FIFOs) mungkin terlihat sama, tetapi dapat disadap.

Solusi-solusi ini juga tidak sepenuhnya aman , tetapi mereka mungkin cukup dekat asalkan Anda tidak berada pada sistem dengan keterbatasan memori yang banyak bertukar.

Idealnya, Anda akan membaca file-file ini (pipa juga file) ke dalam memori yang ditandai dengan mlock (2) sebagai nonswappable, yang biasanya dilakukan oleh program penanganan kata sandi seperti gnupg.

Catatan:

  1. Melewati angka-angka yang diajukan secara teoritis sama baiknya dengan mengarsipkan nama file, tetapi nama file lebih praktis, karena <()memberi Anda nama file, bukan angka yang diajukan (dan coprocmemberi Anda penanda file yang ditandai FD_CLOEXEC , yang membuat file-file tersebut tidak dapat digunakan dalam konteks ini).

  2. Jika Anda menggunakan sistem Linux di mana
    /proc/sys/kernel/yama/ptrace_scopediatur ke 0, maka AFAIK, tidak ada cara antipeluru untuk melindungi diri dari proses lain yang berjalan di bawah pengguna yang sama (mereka dapat menggunakan ptrace untuk melampirkan ke proses Anda dan membaca memori Anda)

  3. Jika Anda hanya perlu menjauhkan kata sandi dari proses yang berjalan di bawah pengguna yang berbeda (bukan root), maka argumen, variabel lingkungan, pipa dan file yang dilindungi izin semua akan dilakukan.

PSkocik
sumber
7

Tidak, variabel lingkungan juga mudah dibaca, dan bocor ke proses anak. melewatinya menggunakan pipa.

Jasen
sumber
2
"variabel lingkungan ... bocor ke proses anak" Itulah inti dari menggunakan variabel lingkungan. Mereka tidak akan berguna jika mereka tidak diwarisi. "variabel lingkungan juga mudah dibaca", tidak, mereka tidak.
Patrick
2
Baca variabelnya, hapus pengaturannya. Itu tidak sulit. Dan Anda bisa menggunakan argumen yang sama tentang pipa. Jika pipa tidak dibaca dari, itu diteruskan ke proses anak, dan proses anak bisa membacanya dan mendapatkan kata sandi.
Patrick
1
@ Patrick Cara terdokumentasi dari variabel lingkungan yang tidak disetel tidak perlu menggosok nilai dari lokasi di mana psdan /procdapat melihatnya.
zwol
1
Apakah beberapa sistem membiarkan Anda membaca variabel lingkungan dari proses arbitrer? Saya tidak berpikir Linux mengizinkannya untuk proses yang dimiliki oleh orang lain, dan jika Anda adalah pengguna yang sama Anda hanya dapat ptrace()target dan membaca ingatannya.
ilkkachu
5
Jawaban ini salah. Variabel lingkungan tidak dapat dibaca oleh pengguna lain.
Gilles 'SANGAT berhenti menjadi jahat'
1

Jika tidak ada yang cocok, pertimbangkan layanan Retensi Kunci Linux (keyrings kernel).

Mulai di: security / keys.txt . Salah satu keyrings default dapat dikloning antara proses induk dan anak.

Ini bukan solusi paling sederhana, tetapi ada di sana dan tampaknya dipelihara & digunakan (itu juga terlibat dalam bug Android tahun lalu.)

Saya tidak tahu tentang status "politik" nya, tetapi saya memiliki kebutuhan yang sama, & mulai bekerja pada ikatan tipu muslihat. Belum menemukan dukungan Perl yang sudah ada.

kzurell
sumber