对于任何命令,有没有办法使用提示符在 bash 中传递敏感数据?

对于任何命令,有没有办法使用提示符在 bash 中传递敏感数据?

假设我用来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用(如果您想在输入中包含换行符,请执行以下操作,如果不想,则执行两次)。catsomecommandCtrl+DReturn

无论您使用什么 shell(只要它是类似 Bourne 或 rc 的 shell),这都可以工作。

一些如果命令前面有空格,则 shell 可能不会将键入的命令保存在其历史文件中。这通常涉及必须设置HISTCONTROL为 value ignorespace。至少OpenBSD 上的bash和支持这一点ksh,但例如ksh93或不支持dashzsh用户可以使用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

如果使用zshbashshell,请使用 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 

相关内容