假设我用来sha1pass
在命令行上生成一些敏感密码的哈希值。我可以用来sha1pass mysecret
生成 的哈希值,mysecret
但这有一个缺点,该缺点mysecret
现在已经存在于 bash 历史记录中。有没有一种方法可以实现此命令的最终目标,同时避免mysecret
以纯文本形式显示(也许通过使用passwd
- 样式提示符)?
我还对一种将敏感数据传递给任何命令的通用方法感兴趣。当敏感数据作为参数(例如 in sha1pass
)或在 STDIN 上传递给某些命令时,该方法会发生变化。
有办法做到这一点吗?
编辑:这个问题引起了很多关注,下面有几个很好的答案。总结就是:
- 按照@Kusalananda的回答,理想情况下,人们永远不必将密码或秘密作为实用程序的命令行参数提供。正如他所描述的,这在几个方面都很容易受到攻击,人们应该使用一种设计更好的实用程序,该实用程序能够获取 STDIN 上的秘密输入
- @vfbsilva 的回答描述如何防止东西被存储在 bash 历史记录中
- @乔纳森的回答描述了一种完美的方法来实现这一点,只要程序可以在 STDIN 上获取其秘密数据。因此,我决定接受这个答案。
sha1pass
在我的 OP 中只是一个例子,但讨论已经确定存在更好的工具来获取 STDIN 上的数据。 - 作为@R..注释中他的回答,对变量使用命令扩展是不是安全的。
所以,总而言之,我接受了@乔纳森的回答因为它是最好的解决方案,因为您有一个设计良好且行为良好的程序可供使用。尽管将密码或秘密作为命令行参数传递从根本上来说是不安全的,但其他答案提供了减轻简单安全问题的方法。
答案1
理想情况下,您永远不要在命令行上键入明文密码作为命令的参数。这样做会使密码成为命令的参数,并且可以通过使用简单的工具(例如ps
或记录到某些审核日志中)在进程表中看到命令行参数。
话虽如此,当然有一些方法可以从 shell 的命令历史记录中隐藏实际密码。
sha1pass "$( head -n 1 )"
然后输入密码并按Enter。此处使用的命令head
仅接受一行输入,并且您键入的最后一个换行符不会成为传递给 的数据的一部分sha1pass
。
为了防止字符回显:
sha1pass "$( stty -echo; head -n 1; stty echo )"
该stty -echo
命令关闭终端上键入字符的回显。然后用 恢复回声stty echo
。
要传递标准输入,可以更改最后一个命令(如果sha1pass
接受标准输入上的数据,您将执行此操作,但看起来好像该特定实用程序忽略其标准输入):
{ stty -echo; head -n 1; stty echo; } | somecommand
如果您需要多行输入(上面假设应传递单行,末尾没有换行符),则head
用(如果您想在输入中包含换行符,请执行以下操作,如果不想,则执行两次)。cat
somecommand
Ctrl+DReturn
无论您使用什么 shell(只要它是类似 Bourne 或 rc 的 shell),这都可以工作。
一些如果命令前面有空格,则 shell 可能不会将键入的命令保存在其历史文件中。这通常涉及必须设置HISTCONTROL
为 value ignorespace
。至少OpenBSD 上的bash
和支持这一点ksh
,但例如ksh93
或不支持dash
。zsh
用户可以使用histignorespace
选项或其HISTORY_IGNORE
变量来定义要忽略的模式。
在支持读取read
而不将字符回显到终端的 shell 中,您还可以使用
IFS= read -rs password # -s turns off echoing in bash or zsh
# -r for reading backslashes as-is,
# IFS= to preserve leading and trailing blanks
sha1pass "$password"
但这显然仍然存在同样的问题,可能会泄露进程表中的密码。
如果实用程序从标准输入读取,并且 shell 支持“here-strings”,则上面的内容可以更改为
IFS= read -rs password
somecommand <<<"$password"
评论摘要如下:
使用在命令行上给出的密码执行命令(除了将数据通过管道传输到命令的命令之外),上述所有命令都会执行此操作,这可能会使密码
ps
对同时运行的任何人可见。但是,如果从交互式 shell 执行,上述命令都不会将输入的密码保存在 shell 的历史文件中。读取明文密码的行为良好的程序是通过从标准输入、文件或直接从终端读取来实现的。
sha1pass
确实需要在命令行上输入密码,可以直接输入密码,也可以使用某种形式的命令替换。如果可能的话,使用其他工具。
答案2
如果使用zsh
或bash
shell,请使用 shell 内置的 -s 选项read
从终端设备读取一行而不回显它。
IFS= read -rs VARIABLE < /dev/tty
然后您可以使用一些奇特的重定向来将该变量用作标准输入。
sha1pass <<<"$VARIABLE"
如果有人运行ps
,他们只会看到“sha1pass”。
假设sha1pass
在未给出任何参数时从 stdin 读取密码(在一行上,忽略行分隔符)。
答案3
如果你HISTCONTROL
这样设置:
HISTCONTROL=ignorespace
并以空格开始命令:
~$ mycommand
它不会被存储在历史记录中。
答案4
只需将值写入文件并传递该文件即可:
$ cat > mysecret
Big seecreeeet!
$ cat mysecret | sha1pass
我不确定如何sha1pass
工作,如果它可以将文件作为输入,您可以使用sha1pass < mysecret
.如果没有,使用cat
可能会出现问题,因为它包含最后的换行符。如果是这种情况,请使用(如果您head
支持-c
):
head -c-1 mysecret | sha1pass