Modo sicuro per passare la password per> 1 programmi in bash


21

Sto scrivendo uno bashscript e devo chiedere all'utente la sua password e passarla a openssl. Mentre opensslposso leggere la password stessa, ho bisogno di due esecuzioni del programma e non voglio chiedere all'utente due volte. Ecco la sceneggiatura:

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

Questo non è sicuro in quanto la password è facilmente disponibile guardando la riga di comando; qualcuno può leggerlo usando ps, per esempio.

opensslposso leggere una password da una variabile d'ambiente, quindi posso sostituirla -k "$PASS"con -pass env:PASS, ma non è ancora sicura; le variabili d'ambiente di qualsiasi processo possono essere lette liberamente (di nuovo, pspossono farlo).

Quindi, come posso passare in sicurezza la password alle due opensslistanze?


combinazione di GnuPG e PinEntry può essere utilizzata qui gnupg.org/related_software/pinentry/index.en.html
Nikhil Mulley

"le variabili d'ambiente di qualsiasi processo possono essere lette liberamente" - questo non è del tutto corretto. pslegge l'ambiente di un processo da /proc/<pid>/environ, ma questo file ha le 0600autorizzazioni, quindi solo root e l'utente che esegue il processo sono in grado di leggere l'ambiente del processo. Direi che è abbastanza sicuro.
Martin von Wittich,

Risposte:


16

Passare la password su un descrittore di file separato dall'input (due volte, una volta per la crittografia e una volta per la decrittografia). Non esportare PASSnell'ambiente.

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

Se il tuo sistema non ha /dev/fd, puoi usare l' -passargomento per dire openssldi leggere la passphrase da un descrittore di file aperto.

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

Come ho capito da un altro la tua risposta , anche nella bashversione con env:PASSè sicuro.

printf '%s\n' "$PASS"non è sicuro. Qualcuno può leggere la riga di comando con psad esempio.

6
@ user14284 No e no. env:PASSnon è sicuro perché la password apparirebbe nell'ambiente del opensslprocesso (non apparirebbe nell'ambiente del bashprocesso, ma non è abbastanza). L'uso printfè sicuro perché è un bash incorporato.
Gilles 'SO- smetti di essere malvagio' il

echo è un bash incorporato, quindi un semplice comando echo non sarebbe sicuro? echo $PASS | openssl .... Non apparirebbe nell'elenco di ps. L'unico posto in cui puoi ottenere il pass sarebbe nella memoria di processo bash. Penso ?
gennaio

1
@gaoithe Sì, echosarebbe sicuro per lo stesso motivo printfè sicuro (e printfnon sarebbe sicuro in una shell in cui non è incorporato). Il motivo per cui uso printfe non echoè che echopuò rovesciare le barre rovesciate (a seconda delle opzioni di bash).
Gilles 'SO- smetti di essere malvagio' il

8

Usando Bash si può fare senza usare printf '%s\n' "$PASS"associando una cosiddetta stringa here ai descrittori di file usando il execcomando incorporato Bash .

Per ulteriori informazioni, consultare: Sicurezza della password dello script Shell dei parametri della riga di comando .

(

# 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

)

1

Mi dispiace, la mia risposta precedente era di openssl man, non i documenti openssl enc.

Questa soluzione non è una pipeline, ma credo che questa soluzione impedisca che la password sia visibile a ps.

Utilizzando un documento qui, openssl vede solo il testo della password.
Finché si è certi di eliminare il file intermedio, non rimane traccia. Forse qualcuno può aiutarti a farlo in una pipeline ed eliminare il file intermedio?

# 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

Questa sarebbe una risposta migliore se spiegasse come utilizzare l'interruttore. Non è sbagliato (tranne per il fatto che il enccomando non ha -knswitch, almeno nelle versioni correnti, è -pass), ma non molto informativo. (Il downvote non è mio.)
Gilles 'SO- smetti di essere malvagio' il

Grazie @Gilles, ho guardato i documenti e ho visto il mio errore, la risposta aggiornata con un approccio diverso.
bsd
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.