将密钥材料传递给 openssl 命令

Tra*_*sen 4 linux security encryption openssl

在 Linux 中通过命令行参数将密钥传递给 openssl 命令是否安全?我知道它会清空实际参数,因此无法通过 /proc 查看它,但是即使如此,是否有某种方法可以利用它?

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

je4*_*e4d 5

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

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


环境:变量

允许您在环境变量中传递凭据。这比使用进程列表更好,因为在 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)
Run Code Online (Sandbox Code Playgroud)

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)
Run Code Online (Sandbox Code Playgroud)

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

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

这样做的一个缺点是,如果传递给 subprocess.Popen,它就不起作用closeFds=true。Subprocess 无法说“不要关闭一个特定的 fd”,因此如果您需要使用 closeFds=true,那么我建议使用file:带有命名管道的语法(如下)。


文件:路径名

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

但是,如果与具有限制性权限的命名管道一起使用,则这与使用上面的选项一样好fd。执行此操作的代码与前面的代码片段类似,只是您需要创建一个 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()
Run Code Online (Sandbox Code Playgroud)

这里print可能会出现与上面调用相同的阻塞 I/O 问题os.write,解决方案也相同。