在bash中为> 1个程序传递密码的安全方法


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
Nikhil Mulley,

“任何进程的环境变量都可以自由读取”-这并不完全正确。ps从中读取进程的环境/proc/<pid>/environ,但是此文件具有0600权限,因此只有root和运行该进程的用户才能读取该进程的环境。我说那很安全。
Martin von Wittich '16

Answers:


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。
吉尔斯(Gillles)“所以-别再邪恶了”

echo是内置的bash,所以简单的echo命令不安全吗?echo $PASS | openssl ...。它不会出现在ps列表中。您唯一可以通过的地方是bash进程内存。我认为 ?
gaoithe

1
@gaoithe是的,echo出于相同的原因,它printf是安全的(也是安全的)(printf在未内置外壳的外壳中也不安全)。我使用printf而不是不使用的原因echoecho可能会反斜杠(取决于bash选项)。
吉尔斯(Gillles)“所以-别再邪恶了”

8

使用Bash可以通过printf '%s\n' "$PASS"使用Bash内置exec命令将所谓的here字符串与文件描述符相关联来实现。

有关更多信息,请参见:命令行参数的Shell脚本密码安全性

(

# 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看到密码。

使用here文档,只有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

如果它解释了如何使用此开关,则将是一个更好的答案。没错(除非该enc命令没有-kn开关,至少在当前版本中是-pass),但信息不是很丰富。(不赞成投票的人不是我的。)
吉尔斯(Gilles)'所以

感谢@Gilles,看了看文档,看到了我的错误,用另一种方法更新了答案。
2012年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.