通过标准输入安全地将密码传递给 openssl

Posted

技术标签:

【中文标题】通过标准输入安全地将密码传递给 openssl【英文标题】:Securely passing password to openssl via stdin 【发布时间】:2011-09-13 08:41:48 【问题描述】:

我们知道我们可以使用以下命令使用 openssl 加密文件:

openssl aes-256-cbc -a -salt -in twitterpost.txt -out foo.enc -pass stdin

密码将从标准输入读取。因此,要预先提供密码,我们需要做的就是预先添加

echo "someGoodPassword" |

到上面的命令。我的问题是:我怎样才能更安全地做到这一点?上面的方法看起来不够安全。

我会感谢一些关于此的 cmets,以便我可以更好地理解这个问题。

【问题讨论】:

【参考方案1】:

将密码放入bash或其他脚本文件,并为其设置600个权限。这将只允许您查看文件,并且不会在任何地方显示密码。

【讨论】:

【参考方案2】:

您使用的几乎所有机制都可以通过 root 进行窥探,因此请记住这一点。

echo 选项将显示在“ps”列表中,使其容易被普通用户窥探和查找密码。

你可以使用-pass file:filename来使用一个文件,所以你可以使用:

sumask=$(umask)
umask 077
rm -f passfile
cat >passfile <<EOM
someGoodPassword
EOM
umask $sumask

这将创建文件,其他帐户无法读取(但 root 仍可读取)。假设该脚本仅用于创建密码文件一次,就好像您重复该过程一样,它往往在一个文件中,因此您需要chmod go-rwx 该文件以使其无法被其他用户读取。

然后你使用:

openssl aes-256-cbc -a -salt -in twitterpost.txt -out foo.enc -pass file:passfile

使用预先创建的密码文件执行加密。

其他机制是 -pass env:ENVVAR 用于使用环境变量(再次将其放入其中而不暴露它是诀窍)

【讨论】:

因此,如果我有一些软件让用户在某些 UI 中输入密码,然后将密码写入此文件(具有正确的权限),然后调用这些终端命令,你会说那是安全的吗?从这个意义上说:如果计算机已被第二个应用程序入侵以获取此密码,那么用户需要担心一些严重的安全问题。实际上,它可能是专门为攻击我自己的软件而设计的一些软件:)您对此有何看法? 这会让事情变得相对安全,但是如果有一个专门设计用来攻击你的程序的应用程序,那么所有的赌注都没有了 - 我们可以在输入密码时窥探键盘,我们可以读取写入文件时的 I/O,我们可以读取文件,我们可以读取您的环境。几乎没有 100% 安全的保护措施 - 您可以使用“打开文件,取消链接但保持文件句柄打开并传递句柄”技巧,因此文件系统上没有密码痕迹(使用 fd:number 作为-pass 的参数)带有 UI 的应用程序也使用 fd 如果这是 gnome 桌面应用程序的一部分,您可以使用 gnome-keyring 作为密码的安全存储位置,因为它是加密的,并且在用户未登录时通常无法访问( KDE 有 kwallet IIRC)。 Adobe AIR 应用程序也有密码存储机制(我不知道 AIR 的保护机制),但由于您使用的是 shell 脚本习惯用法,我希望这些不是真正的选择。 echo 没有出现在 ps 列表中,因为它是内置的(至少在 bash 中) @AndreKR pkcs12 支持使用密码进行读写,这就是为什么有单独的选项(-passin-passout)。这是针对aes-256-cbc 命令的,它只需要一个参数。【参考方案3】:

短版

使用命名管道。

openssl aes-256-cbc -a -salt -in twitterpost.txt -out foo.enc -pass file:<( echo -n "someGoodPassword" )

加长版

使用命名管道。您可以使用 bash 在 bash 中创建它

<( *output* )

例如

<( echo -n "content" ) # without -n echo will add a newline

它会打开一个命名管道,通常是一个先进先出队列,你会在进程列表上看到类似的东西

/dev/fd/63

只有当前用户可以读取,读取后会自动关闭,所以不用担心权限和清理磁盘(如果程序崩溃管道会关闭,而您在另一个答案中建议创建的文件将保留在磁盘上)。

这样它就会以最快的方式关闭,就在命令读取它之后,而不是等待它完成他的任务(我刚刚做了一个测试:加密一些千兆字节并尝试读取命名管道(它在进程列表):命名管道会立即关闭,即使 openssl 需要很长时间才能加密)。

关于您的 cmets

如果计算机已被第二个应用程序入侵以获取此 密码,那么用户需要担心一些严重的安全问题 关于。实际上,它可能是一些专门设计用于 攻击我自己的软件

如果您的计算机被黑客入侵并且攻击者拥有与您相同的用户权限,那么您就完蛋了。例如,攻击者可以轻松地将您的 .bashrc 修改为别名 openssl,以便它启动一个假设的“evil-openssl”,在将所有内容处理到真正的 openssl 之前复制您的密码和数据,从而给您留下虚假的安全感。

也就是说,我不是安全专家,所以如果有人想对我投反对票(并告诉我原因),不客气。

【讨论】:

【参考方案4】:

如果我没听错的话,你的演唱会是关于

$ echo "someGoodPassword" | openssl (...) -pass stdin

是密码将在进程列表中对所有用户可见一小段时间。这可以通过 bash 的 &lt;&lt;&lt; 重定向轻松解决(但在普通的旧 POSIX shell 中不起作用):

$ openssl (...) -pass stdin <<<"someGoodPassword"

此构造支持变量插值 (&lt;&lt;&lt;"$password"),命令输出可以进一步通过管道传输或像往常一样重定向到文件。

【讨论】:

【参考方案5】:

您可以使用多种方法来传递密码:https://www.openssl.org/docs/man1.0.2/apps/openssl.html#PASS-PHRASE-ARGUMENTS

正如@Petesh 所说,root 可以阅读所有内容!

因此,如果您将密码写到任何通用(!)文件中,例如

进入具有任何安全权限的临时文件 或进入脚本,你的 echo 会在管道中做什么

root 用户可以找到这个!

不喜欢使用/proc 提供的所有东西(例如ps

所以,不要使用...

openssl aes-256-cbc ... -passin 'pass:someGoodPassword'

PASSWORD='someGoodPassword'
openssl aes-256-cbc ... -passin 'env:PASSWORD'`

最佳解决方案

避免在系统上以纯文本形式存储密码(例如,使用密码管理器)

通过管道/fifo 将密码传递给openssl

password_manager get_password | openssl aes-256-cbc ... -passin 'stdin'

# https://***.com/a/7082184/1108919
password_manager get_password >&3
openssl aes-256-cbc ... -passin 'fd:3'

openssl aes-256-cbc ... -passin "file:<(password_manager get_password)"

【讨论】:

以上是关于通过标准输入安全地将密码传递给 openssl的主要内容,如果未能解决你的问题,请参考以下文章

将输入从标准输入传递到函数时进行缓冲

OpenSSL 功能介绍

Python子进程错误:使用标准输入将输入传递到终端

linux系统安全标准规范

OpenSSL 功能介绍

杀死父进程后将标准输入传递给子进程