Bezpieczny sposób na podanie hasła dla> 1 programów w bash

21

Piszę bashskrypt i muszę zapytać użytkownika o hasło i przekazać je openssl. Chociaż opensslmogę odczytać samo hasło, potrzebuję dwóch uruchomień programu i nie chcę pytać użytkownika dwukrotnie. Oto skrypt:

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

Nie jest to bezpieczne, ponieważ hasło jest łatwo dostępne, patrząc w wierszu poleceń; na przykład ktoś może to przeczytać ps.

opensslmoże odczytać hasło ze zmiennej środowiskowej, więc mogę wymienić -k "$PASS"z -pass env:PASS, ale wciąż nie jest bezpieczne; zmienne środowiskowe dowolnego procesu można odczytać dowolnie (ponownie, psmożna to zrobić).

Jak mogę bezpiecznie przekazać hasło do obu opensslinstancji?

Chris Down
źródło
kombinacja GnuPG i PinEntry może być tutaj użyta gnupg.org/related_software/pinentry/index.en.html
Nikhil Mulley
„zmienne środowiskowe dowolnego procesu można odczytać swobodnie” - nie jest to do końca poprawne. psodczytuje środowisko procesu /proc/<pid>/environ, ale ten plik ma 0600uprawnienia, więc tylko root i użytkownik uruchamiający proces są w stanie odczytać środowisko procesu. Powiedziałbym, że to całkiem bezpieczne.
Martin von Wittich,

Odpowiedzi:

16

Przekaż hasło do oddzielnego deskryptora pliku od danych wejściowych (dwa razy, raz dla szyfrowania i raz dla odszyfrowania). Nie eksportuj PASSdo środowiska.

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

Jeśli twój system nie ma /dev/fd, możesz użyć -passargumentu , opensslaby odczytać hasło z otwartego deskryptora pliku.

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- przestań być zły”
źródło
Jak rozumiem z twojej odpowiedzi , również w bashwersji z env:PASSjest bezpieczny.
printf '%s\n' "$PASS"nie jest bezpieczne. Ktoś może psna przykład odczytać wiersz poleceń .
6
@ user14284 Nie i nie. env:PASSnie jest bezpieczne, ponieważ hasło pojawi się w środowisku opensslprocesu (nie pojawi się w środowisku bashprocesu, ale to nie wystarczy). Korzystanie printfjest bezpieczne, ponieważ jest wbudowane w bash.
Gilles „SO- przestań być zły”
echo jest wbudowane w bash, więc czy proste polecenie echa nie byłoby bezpieczne? echo $PASS | openssl .... Nie pojawiłby się na liście ps. Jedynym miejscem, które można uzyskać, jest pamięć procesu bash. Myślę ?
Czwartek
1
@ gaoithe Tak, echobyłby bezpieczny z tego samego powodu printfjest bezpieczny (i printfnie byłby bezpieczny w powłoce, w której nie jest wbudowany). Powodem, dla którego używam, printfa nie nie, echojest to, że echomoże to powodować odwrotne ukośniki odwrotne (w zależności od opcji bash).
Gilles „SO- przestań być zły”
8

Za pomocą Bash można to zrobić bez użycia printf '%s\n' "$PASS", łącząc tak zwany tutaj ciąg znaków z deskryptorami plików za pomocą wbudowanego execpolecenia Bash .

Aby uzyskać więcej informacji, zobacz: Zabezpieczenie hasła skryptu powłoki parametrami wiersza polecenia .

(

# 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
źródło
1

Przepraszam, moja poprzednia odpowiedź pochodziła od openssl man, a nie od openssl enc docs.

To rozwiązanie nie jest potokiem, ale wierzę, że to rozwiązanie zapobiega widoczności hasła dla ps.

Korzystając z dokumentu tutaj, openssl widzi tylko tekst hasła.
Tak długo, jak masz pewność, że plik pośredni zostanie wyeliminowany, nie pozostanie żaden ślad. Może ktoś może pomóc to zrobić w potoku i wyeliminować plik pośredni?

# 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
źródło
To byłaby lepsza odpowiedź, gdyby wyjaśniła, jak używać przełącznika. To nie jest złe (z wyjątkiem tego, że encpolecenie nie ma -knprzełącznika, przynajmniej w obecnych wersjach, ale -pass), ale nie bardzo pouczające. (Głos nie jest mój.)
Gilles „SO- przestań być zły”
Dzięki @Gilles, przejrzałem dokumenty i zobaczyłem mój błąd, zaktualizowałem odpowiedź z innym podejściem.
bsd