Безопасный способ передать пароль для> 1 программ в Bash

21

Я пишу bashскрипт, и мне нужно спросить у пользователя его пароль и передать его openssl. Хотя opensslсам пароль могу прочитать, мне нужно два прогона программы, и я не хочу спрашивать пользователя дважды. Вот сценарий:

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

Это небезопасно, так как пароль легко получить, посмотрев на командную строку; кто-то может прочитать это ps, например.

opensslможет прочитать пароль из переменной окружения, так что я могу заменить -k "$PASS"с -pass env:PASS, но это по - прежнему не безопасно; переменные окружения любого процесса могут быть прочитаны свободно (опять же, это psможно сделать).

Итак, как я могу безопасно передать пароль для двух opensslэкземпляров?

Крис Даун
источник
Сочетание GnuPG и PinEntry можно использовать здесь gnupg.org/related_software/pinentry/index.en.html
Никхил Мулли,
«Переменные среды любого процесса могут быть прочитаны свободно» - это не совсем правильно. psчитает среду процесса /proc/<pid>/environ, но у этого файла есть 0600разрешения, поэтому только пользователь root и пользователь, выполняющий процесс, могут читать среду процесса. Я бы сказал, что это довольно безопасно.
Мартин фон Виттих

Ответы:

16

Передайте пароль в отдельном файловом дескрипторе от входа (дважды, один раз для шифрования и один раз для дешифрования). Не экспортировать PASSв окружающую среду.

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

Если ваша система не имеет /dev/fd, вы можете использовать -passаргумент, чтобы сказать, opensslчтобы прочитать фразу-пароль из дескриптора открытого файла.

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
Жиль "ТАК - прекрати быть злым"
источник
Как я понял из другого вашего ответа , в bashверсии с env:PASSтоже безопасно.
printf '%s\n' "$PASS"не безопасно Кто-нибудь может прочитать командную строку, psнапример.
6
@ user14284 Нет и нет. env:PASSне является безопасным, потому что пароль появится в среде opensslпроцесса (он не появится в среде bashпроцесса, но этого недостаточно). Использование printfбезопасно, поскольку оно встроено в bash.
Жиль "ТАК - перестань быть злым"
echo - это встроенная команда bash, поэтому не будет ли простая команда echo безопасной? echo $PASS | openssl ..., Это не будет отображаться в списке PS. Единственное место, которое вы можете получить - это память процесса bash. Я думаю ?
Гаоит
1
@gaoithe Да, echoбыло бы безопасно по той же причине printfбезопасно (и printfне было бы безопасно в оболочке, где она не встроена). Причина, по которой я пользуюсь, printfа не нет, echoзаключается в том, что echoможет искажать обратную косую черту (в зависимости от параметров bash).
Жиль "ТАК - перестань быть злым"
8

Используя Bash, это можно сделать без использования printf '%s\n' "$PASS", связав так называемую здесь строку с файловыми дескрипторами, используя встроенную execкоманду Bash .

Для получения дополнительной информации см .: Защита паролем сценария командной строки параметров командной строки .

(

# 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

Извините, мой предыдущий ответ был от openssl man, а не от openssl enc docs.

Это решение не является конвейером, но я считаю, что это решение предотвращает видимость пароля для PS.

Используя здесь документ, только openssl видит текст пароля.
Пока вы уверены, что удалите промежуточный файл, никаких следов не останется. Может быть, кто-то может помочь сделать это в конвейере и устранить промежуточный файл?

# 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
источник
Это было бы лучшим ответом, если бы в нем объяснялось, как использовать коммутатор. Это не так (за исключением того, что encкоманда не имеет -knпереключателя, по крайней мере, в текущих версиях -pass), но не очень информативно. (Понижение не мое.)
Жиль "
Спасибо @Gilles, посмотрел документы и увидел мою ошибку, обновил ответ с другим подходом.
BSD