通过标准输入安全地将密码传递给 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 的 <<<
重定向轻松解决(但在普通的旧 POSIX shell 中不起作用):
$ openssl (...) -pass stdin <<<"someGoodPassword"
此构造支持变量插值 (<<<"$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的主要内容,如果未能解决你的问题,请参考以下文章