Manière sûre de passer le mot de passe pour> 1 programmes dans bash

21

J'écris un bashscript et je dois demander à l'utilisateur son mot de passe et le transmettre à openssl. Bien que opensslje puisse lire le mot de passe lui-même, j'ai besoin de deux exécutions du programme et je ne veux pas demander à l'utilisateur deux fois. Voici le script:

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

Ce n'est pas sûr car le mot de passe est facilement accessible en regardant la ligne de commande; quelqu'un peut le lire en utilisant ps, par exemple.

opensslpeut lire un mot de passe à partir d'une variable d'environnement, donc je peux le remplacer -k "$PASS"par -pass env:PASS, mais ce n'est toujours pas sûr; les variables d'environnement de n'importe quel processus peuvent être lues librement (encore une fois, pspeuvent le faire).

Alors, comment puis-je transmettre le mot de passe en toute sécurité aux deux opensslinstances?

Chris Down
la source
la combinaison de GnuPG et PinEntry peut être utilisée ici gnupg.org/related_software/pinentry/index.fr.html
Nikhil Mulley
"les variables d'environnement de n'importe quel processus peuvent être lues librement" - ce n'est pas tout à fait correct. pslit l'environnement d'un processus à partir de /proc/<pid>/environ, mais ce fichier a des 0600autorisations, donc seuls root et l'utilisateur exécutant le processus peuvent lire l'environnement du processus. Je dirais que c'est assez sûr.
Martin von Wittich

Réponses:

16

Passez le mot de passe sur un descripteur de fichier distinct de l'entrée (deux fois, une fois pour le chiffrement et une fois pour le déchiffrement). N'exportez pas PASSvers l'environnement.

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

Si votre système n'en a pas /dev/fd, vous pouvez utiliser l' -passargument pour indiquer opensslde lire la phrase secrète à partir d'un descripteur de fichier ouvert.

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 'SO- arrête d'être méchant'
la source
Si je comprends bien d' un autre votre réponse , dans la bashversion avec env:PASSest également sûr.
printf '%s\n' "$PASS"n'est pas sûr. Quelqu'un peut lire la ligne de commande avec pspar exemple.
6
@ user14284 Non et non. env:PASSn'est pas sûr car le mot de passe apparaîtrait dans l'environnement du opensslprocessus (il n'apparaîtrait pas dans l'environnement du bashprocessus, mais ce n'est pas suffisant). L'utilisation printfest sûre car c'est un bash intégré.
Gilles 'SO- arrête d'être méchant'
echo est un bash intégré, donc une simple commande echo ne serait-elle pas sûre? echo $PASS | openssl .... Il n'apparaîtrait pas dans la liste ps. Le seul endroit où vous pouvez passer serait dans la mémoire du processus bash. Je pense ?
gaoithe
1
@gaoithe Oui, echoserait sûr pour la même raison printfest sûr (et printfne serait pas sûr dans un shell où il n'est pas intégré). La raison pour laquelle j'utilise printfet non echoest que cela echopeut modifier les barres obliques inverses (selon les options de bash).
Gilles 'SO- arrête d'être méchant'
8

En utilisant Bash, cela peut être fait sans utiliser printf '%s\n' "$PASS"en associant une soi-disant chaîne ici avec des descripteurs de fichiers en utilisant la execcommande intégrée Bash .

Pour plus d'informations, voir: Sécurité du mot de passe du script shell des paramètres de ligne de commande .

(

# 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
la source
1

Désolé, ma réponse précédente venait de openssl man, pas des documents openssl enc.

Cette solution n'est pas un pipeline, mais je pense que cette solution empêche le mot de passe d'être visible par ps.

En utilisant un document ici, seul openssl voit le texte du mot de passe.
Tant que vous êtes certain d'éliminer le fichier intermédiaire, aucune trace ne reste. Peut-être que quelqu'un peut aider à le faire dans un pipeline et éliminer le fichier intermédiaire?

# 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
la source
Ce serait une meilleure réponse si elle expliquait comment utiliser le commutateur. Ce n'est pas faux (sauf que la enccommande n'a pas de -kncommutateur, du moins sur les versions actuelles, c'est le cas -pass), mais pas très informatif. (Le downvote n'est pas le mien.)
Gilles 'SO- arrête d'être méchant'
Merci @Gilles, regardé les documents et vu ma bévue, réponse mise à jour avec une approche différente.
bsd