cem*_*ate 50 shell security password
假设我使用sha1pass
在命令行上生成一些敏感密码的哈希值。我可以sha1pass mysecret
用来生成一个散列,mysecret
但这有一个mysecret
现在在 bash 历史中的缺点。有没有办法在避免mysecret
以纯文本显示的同时实现此命令的最终目标,也许是通过使用passwd
-style 提示?
我也对将敏感数据传递给任何命令的通用方法感兴趣。当敏感数据作为参数(例如 in sha1pass
)或在 STDIN 上传递给某个命令时,该方法会发生变化。
有没有办法做到这一点?
编辑:这个问题引起了很多关注,下面提供了几个很好的答案。总结如下:
sha1pass
在我的 OP 中只是一个例子,但讨论已经确定存在更好的工具来获取 STDIN 上的数据。所以,总而言之,我接受了@Jonathan 的回答,因为这是最好的解决方案,因为您有一个设计良好且行为良好的程序可供使用。尽管将密码或机密作为命令行参数传递从根本上说是不安全的,但其他答案提供了减轻简单安全问题的方法。
Kus*_*nda 40
理想情况下,您永远不要在命令行上键入明文密码作为命令的参数。这样做会使密码成为命令的参数,并且可以通过使用简单的工具(例如ps
或登录到某些审计日志)在进程表中看到命令行参数。
话虽如此,当然有办法从 shell 的命令历史中隐藏实际密码。
sha1pass "$( head -n 1 )"
Run Code Online (Sandbox Code Playgroud)
然后输入密码并按Enter。head
此处使用的命令仅接受一行输入,并且您键入的最后一个换行符将不是传递给 的数据的一部分sha1pass
。
为了防止字符回显:
sha1pass "$( stty -echo; head -n 1; stty echo )"
Run Code Online (Sandbox Code Playgroud)
该stty -echo
命令关闭终端上键入的字符的回显。然后用 恢复回声stty echo
。
要传递标准输入,可以更改最后一个命令(如果sha1pass
接受标准输入上的数据,您会这样做,但似乎此特定实用程序忽略了其标准输入):
{ stty -echo; head -n 1; stty echo; } | somecommand
Run Code Online (Sandbox Code Playgroud)
如果你需要多行输入(上述假设一行应传递,并在最后没有换行符),则更换整个head
使用命令cat
并终止输入(假设somecommand
本身读取,直到结束文件)与Ctrl+D(Return如果您想在输入中包含换行符,请跟随,否则两次)。
无论您使用什么外壳,这都可以工作(只要它是类似 Bourne 或类似 rc 的外壳)。
如果命令前面有一个空格,则某些shell 可能不会将键入的命令保存在其历史文件中。这通常涉及必须设置HISTCONTROL
为 value ignorespace
。这至少在 OpenBSD 上支持bash
和ksh
,但不支持 egksh93
或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"
Run Code Online (Sandbox Code Playgroud)
但这显然仍然存在与可能在进程表中泄露密码相同的问题。
如果实用程序从标准输入读取,并且 shell 支持“here-strings”,则上述内容可以更改为
IFS= read -rs password
somecommand <<<"$password"
Run Code Online (Sandbox Code Playgroud)
评论摘要如下:
使用命令行上给出的密码执行命令,除了将数据通过管道传输到命令的命令外,上述所有命令都执行该命令,可能会使ps
同时运行的任何人都可以看到密码。但是,如果从交互式 shell 执行,上述命令都不会将键入的密码保存在 shell 的历史文件中。
读取明文密码的行为良好的程序通过从其标准输入、文件或直接从终端读取来实现。
sha1pass
确实需要在命令行上输入密码,直接输入或使用某种形式的命令替换。
如果可能,请使用其他工具。
vfb*_*lva 26
如果你这样设置HISTCONTROL
:
HISTCONTROL=ignorespace
Run Code Online (Sandbox Code Playgroud)
并以空格开始命令:
~$ mycommand
Run Code Online (Sandbox Code Playgroud)
它不会存储在历史记录中。
小智 26
如果使用zsh
or bash
shell,请使用read
shell 内置选项的 -s 选项从终端设备读取一行而不回显它。
IFS= read -rs VARIABLE < /dev/tty
Run Code Online (Sandbox Code Playgroud)
然后你可以使用一些奇特的重定向来将变量用作标准输入。
sha1pass <<<"$VARIABLE"
Run Code Online (Sandbox Code Playgroud)
如果有人运行ps
,他们将看到的只是“sha1pass”。
这假设sha1pass
在没有给出任何参数时从 stdin 读取密码(在一行上,忽略行分隔符)。
R..*_*ICE 10
通过管道或 here-doc 传递敏感数据:
command_with_secret_output | command_with_secret_input
Run Code Online (Sandbox Code Playgroud)
或者:
command_with_secret_input <<EOF
$secret
EOF
Run Code Online (Sandbox Code Playgroud)
秘密位于(非导出的)shell 变量中是可以的,但是您永远不能在命令行上使用这些变量,只能在此处的文档和 shell 内部使用。
正如 Kusalananda 在评论中指出的那样,如果您在交互式 shell 中输入命令,您为 here 文档输入的行将存储在 shell 历史记录中,因此在那里输入密码是不安全的,但它仍然应该是安全地使用包含秘密的 shell 变量;历史将包含文本$secret
而不是$secret
扩展到的任何内容。
使用命令扩展是不安全的:
command_with_secret_input "$(command_with_secret_output)"
Run Code Online (Sandbox Code Playgroud)
因为输出将包含在命令行中并在ps
输出中可见(或手动从 /proc 读取),但在具有强化 /proc 的系统上除外。
给变量赋值也是可以的:
secret=$(command_with_secret_output)
Run Code Online (Sandbox Code Playgroud)
只需将值写入文件并传递文件:
$ cat > mysecret
Big seecreeeet!
$ cat mysecret | sha1pass
Run Code Online (Sandbox Code Playgroud)
我不确定sha1pass
它是如何工作的,如果它可以将文件作为输入,则可以使用sha1pass < mysecret
. 如果没有,使用cat
可能会出现问题,因为它包含最后的换行符。如果是这种情况,请使用(如果您head
支持-c
):
head -c-1 mysecret | sha1pass
Run Code Online (Sandbox Code Playgroud)