Maneira segura de passar a senha para 1 programas no bash

18

Estou escrevendo um script bash e preciso perguntar a senha do usuário e passá-lo para openssl . Enquanto openssl pode ler a senha em si, eu preciso de duas execuções do programa e não quero perguntar ao usuário duas vezes. Aqui está o 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

Isso não é seguro, pois a senha está facilmente disponível, olhando para a linha de comando; alguém pode lê-lo usando ps , por exemplo.

openssl pode ler uma senha de uma variável de ambiente, então posso substituir -k "$PASS" por -pass env:PASS , mas ainda não é seguro; as variáveis de ambiente de qualquer processo podem ser lidas livremente (novamente, ps pode fazer isso).

Então, como posso passar a senha com segurança para as duas openssl instances?

    
por Chris Down 14.01.2012 / 13:34

3 respostas

15

Passe a senha em um descritor de arquivo separado da entrada (duas vezes, uma para criptografia e uma para descriptografia). Não exporte PASS para o 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 o seu sistema não tiver /dev/fd , você poderá usar o -pass argumento informar openssl para ler a senha de um descritor de arquivo aberto.

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
    
por 15.01.2012 / 03:22
6

Usando o Bash, isso pode ser feito sem usar printf '%s\n' "$PASS" , associando uma chamada string here a descritores de arquivos usando o comando Bash builtin exec .

Para obter mais informações, consulte: Segurança da senha do script shell da linha de comando parâmetros .

(

# 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

)
    
por 15.01.2012 / 17:59
1

Desculpe, minha resposta anterior era do openssl man, não dos documentos openssloc.

Esta solução não é um pipeline, mas acredito que esta solução impeça que a senha seja visível para ps.

Usando um documento aqui, apenas o openssl vê o texto da senha.
Contanto que você esteja certo de eliminar o arquivo intermediário, nenhum vestígio permanece. Talvez alguém possa ajudar a fazer isso em um pipeline e eliminar o arquivo intermediário?

# 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
    
por 14.01.2012 / 13:44