Cara aman untuk menyampaikan kata sandi untuk> 1 program di bash

21

Saya sedang menulis bashskrip, dan perlu meminta kata sandi pengguna dan meneruskannya kepada openssl. Sementara openssldapat membaca kata sandi itu sendiri, saya perlu dua kali menjalankan program dan tidak ingin bertanya kepada pengguna dua kali. Ini skripnya:

cp file{,.old}
read -sp 'Enter password. ' PASS; echo
export PASS

# decode | edit | encode
openssl enc -d -aes-256-cbc -k "$PASS" -in file.old | \
  sed ... | openssl enc -e -aes-256-cbc -k "$PASS" -out file

unset PASS

Ini tidak aman karena kata sandi mudah tersedia dengan melihat baris perintah; seseorang dapat membacanya menggunakan ps, misalnya.

openssldapat membaca kata sandi dari variabel lingkungan, jadi saya dapat menggantinya -k "$PASS"dengan -pass env:PASS, tetapi masih belum aman; variabel lingkungan dari setiap proses dapat dibaca secara bebas (sekali lagi, psdapat melakukannya).

Jadi, bagaimana saya bisa meneruskan kata sandi dengan aman ke dua opensslcontoh?

Chris Down
sumber
kombinasi GnuPG dan PinEntry dapat digunakan di sini gnupg.org/related_software/pinentry/index.en.html
Nikhil Mulley
"variabel lingkungan dari setiap proses dapat dibaca secara bebas" - ini tidak sepenuhnya benar. psmembaca lingkungan dari suatu proses /proc/<pid>/environ, tetapi file ini memiliki 0600izin, jadi hanya root dan pengguna yang menjalankan proses dapat membaca lingkungan proses. Menurut saya itu cukup aman.
Martin von Wittich

Jawaban:

16

Pass password pada deskriptor file terpisah dari input (dua kali, sekali untuk enkripsi dan sekali untuk dekripsi). Jangan ekspor PASSke lingkungan.

read -sp 'Enter password. ' PASS
printf '%s\n' "$PASS" |
openssl enc -d -aes-256-cbc -kfile /dev/stdin -in file.old |
sed ... | {
  printf '%s\n' "$PASS" |
  openssl enc -e -aes-256-cbc -kfile /dev/stdin -in /dev/fd/3 -out file;
} 3<&0

Jika sistem Anda tidak memiliki /dev/fd, Anda dapat menggunakan -passargumen untuk memberitahu openssluntuk membaca kata sandi dari deskriptor file terbuka.

printf '%s\n' "$PASS" | {
  printf '%s\n' "$PASS" |
  openssl enc -d -aes-256-cbc -pass fd:0 -in file.old |
  tr a-z A-Z | tee /dev/tty | {
  openssl enc -e -aes-256-cbc -pass fd:3 -out file; }
} 3<&0
Gilles 'SANGAT berhenti menjadi jahat'
sumber
Seperti yang saya mengerti dari jawaban Anda yang lain , dalam bashversi dengan env:PASSaman juga.
printf '%s\n' "$PASS"tidak aman. Seseorang dapat membaca baris perintah dengan psmisalnya.
6
@ user14284 Tidak, dan tidak. env:PASStidak aman karena kata sandi akan muncul di lingkungan opensslproses (tidak akan muncul di lingkungan bashproses, tetapi itu tidak cukup). Penggunaannya printfaman karena merupakan bash built-in.
Gilles 'SANGAT berhenti menjadi jahat'
gema adalah bash bawaan, jadi bukankah perintah gema sederhana aman? echo $PASS | openssl .... Itu tidak akan muncul dalam daftar ps. Satu-satunya tempat Anda bisa mendapatkan akan berada dalam memori proses bash. Kupikir ?
gaoithe
1
@gaoithe Ya, echoakan aman karena alasan yang sama printfaman (dan printftidak akan aman di shell di mana ia tidak dibangun). Alasan saya menggunakan printfdan tidak echoadalah karena echodapat memotong backslash (tergantung pada opsi bash).
Gilles 'SO- stop being evil'
8

Menggunakan Bash dapat dilakukan tanpa menggunakan printf '%s\n' "$PASS"dengan menghubungkan string yang disebut di sini dengan deskriptor file menggunakan perintah Bash builtin exec.

Untuk informasi lebih lanjut, lihat: Keamanan kata sandi script shell parameter parameter baris perintah .

(

# sample code to edit password-protected file with openssl
# user should have to enter password only once
# password should not become visible using the ps command

echo hello > tmp.file

#env -i bash --norc   # clean up environment
set +o history
unset PASS || exit 1

read -sp 'Enter password. ' PASS; echo

# encrypt file and protect it by given password
exec 3<<<"$PASS"
openssl enc -e -aes-256-cbc -pass fd:3  -in tmp.file -out file

cp file{,.old}

# decode | edit | encode
exec 3<<<"$PASS" 4<<<"$PASS"
openssl enc -d -aes-256-cbc -pass fd:3 -in file.old | 
   sed 's/l/L/g' | 
   openssl enc -e -aes-256-cbc -pass fd:4 -out file

exec 3<<<"$PASS"
openssl enc -d -aes-256-cbc -pass fd:3 -in file

rm -P tmp.file file.old
unset PASS

)
jon
sumber
1

Maaf, jawaban saya sebelumnya adalah dari openssl man, bukan the openssl enc docs.

Solusi ini bukan saluran pipa, tapi saya percaya solusi ini mencegah kata sandi terlihat oleh ps.

Menggunakan dokumen di sini, hanya openssl yang melihat teks kata sandi.
Selama Anda yakin untuk menghilangkan file perantara, tidak ada jejak yang tersisa. Mungkin seseorang dapat membantu melakukan ini dalam saluran pipa dan menghilangkan file perantara?

# cp file{,.old}  don't need this anymore since intermediate becomes same
read -sp 'Enter password. ' PASS; echo
#no need to export, env's are readable, as mentioned

# decode into intermediate file
openssl <<HERE 2>&1 >/dev/null
enc -d -aes-256-cbc -k "$PASS" -in file -out intermediate
HERE

# edit intermediate

# encode intermediate back into file
openssl <<HERE 2>&1 >/dev/null
enc -e -aes-256-cbc -k "$PASS" -in intermediate -out file 
HERE
unset PASS
rm -f intermediate
bsd
sumber
Ini akan menjadi jawaban yang lebih baik jika menjelaskan cara menggunakan sakelar. Itu tidak salah (kecuali bahwa encperintah tidak memiliki -knsaklar, setidaknya pada versi saat ini, itu -pass), tetapi tidak terlalu informatif. (Suara turunnya bukan milikku.)
Gilles 'SANGAT berhenti menjadi jahat'
Terima kasih @Gilles, melihat dokumen dan melihat kesalahan saya, jawaban yang diperbarui dengan pendekatan yang berbeda.
bsd