将密钥材料传递给openssl命令

时间:2012-03-08 22:11:10

标签: linux security encryption openssl

通过Linux中的命令行参数将密钥传递给openssl命令是否安全?我知道它会使实际参数无效,所以无法通过/ proc查看,但是,即便如此,有没有办法利用它?

我有一个python应用程序,我想使用OpenSSL通过子进程中的stdin / stdout流进行加密/描述,但我想知道我的密钥是安全的。

2 个答案:

答案 0 :(得分:3)

在命令行上传递凭据并不安全。这将导致您的密码在系统的流程列表中可见 - 即使openssl尽快从流程列表中删除它,它也会立即存在。

openssl为您提供了几种传递凭据的方法 - 该手册页有一个名为“PASS PHRASE ARGUMENTS”的部分,该部分记录了您可以将凭据传递到openssl的所有方法。我将解释相关的内容:


<强> ENV:VAR

允许您在环境变量中传递凭据。这比使用进程列表更好,因为在Linux上,默认情况下其他用户无法读取进程的环境 - 但在其他平台上并不一定如此。

缺点是以同一用户或root身份运行的其他进程将能够通过/ proc轻松查看密码。

使用python的子进程非常容易:

new_env=copy.deepcopy(os.environ)
new_env["MY_PASSWORD_VAR"] = "my key data"
p = subprocess.Popen(["openssl",..., "-passin", "env:MY_PASSWORD_VAR"], env=new_env)

<强> FD:编号

这使您可以告诉openssl从文件描述符中读取凭据,它将假定已经打开以供阅读。通过使用它,您可以将关键数据直接从您的进程写入openssl,具体如下:

r, w = os.pipe()
p = subprocess.Popen(["openssl", ..., "-passin", "fd:%i" % r], preexec_fn=lambda:os.close(w))
os.write(w, "my key data\n")
os.close(w)

这将使您的密码与同一系统上的其他用户保持安全,假设他们使用其他帐户登录。

使用上面的代码,您可能会遇到os.write呼叫阻止问题。如果openssl在读取密钥之前等待其他事情发生,就会发生这种情况。这可以通过异步i / o(例如选择循环)或额外线程来解决,以执行write()&amp; close( )。

这样做的一个缺点是,如果将closeFds=true传递给subprocess.Popen,它就不起作用。子进程无法说“不要关闭一个特定的fd”,所以如果你需要使用closeFds = true,那么我建议使用file:语法(下面)和命名管道。


文件路径名:

不要将它与实际文件一起使用来存储密码!应该避免这种情况,例如:您的程序可能会在删除文件之前被终止,而对于大多数日志文件系统,几乎不可能真正擦除磁盘中的数据。

但是,如果与具有限制权限的命名管道一起使用,则可以使用上面的fd选项。执行此操作的代码与之前的代码段类似,只是您需要create a fifo而不是使用os.pipe()

pathToFifo = my_function_that_securely_makes_a_fifo()
p = subprocess.Popen(["openssl", ..., "-passin", "file:%s" % pathToFifo])
fifo = open(pathToFifo, 'w')
print >> fifo, "my key data"
fifo.close()

此处print可能与上面的os.write调用具有相同的阻止I / O问题,分辨率也相同。

答案 1 :(得分:2)

不,这不安全。无论openssl在开始运行后对其命令行执行什么操作,仍然有一个时间窗口,在该窗口期间,信息在进程的命令行中可见:在进程启动之后且有机会为null之前它出来了。

另外,有很多方法可以发生事故:例如,命令行在执行之前由sudo记录,或者最终在shell历史文件中记录。

Openssl支持大量传递敏感信息的方法,因此您无需在命令行中将其清除。从联机帮助页:

  • <强>通过:密码

    实际密码是密码。由于密码对于实用程序是可见的(例如Unix下的'ps'),因此只应在安全性不重要的地方使用此表单。

  • env:var

    从环境变量var获取密码。由于其他进程的环境在某些平台上可见(例如某些Unix操作系统下的ps),因此应谨慎使用此选项。

  • 文件路径名:

    路径名的第一行是密码。如果为-passin和-passout参数提供了相同的pathname参数,则第一行将用于输入密码,下一行将用于输出密码。 pathname不需要引用常规文件:例如,它可以引用设备或命名管道。

  • fd:数字

    从文件描述符编号中读取密码。例如,这可用于通过管道发送数据。

  • stdin

    从标准输入中读取密码。

除前两个选项外,所有选项都很好。