如何将密码传递给子进程?

por*_*ton 19 environment-variables ipc fork

在命令行上传递密码(到从我的程序启动的子进程)被认为是不安全的(因为它甚至可以被使用 ps 命令的其他用户看到)。可以将其作为环境变量传递吗?

我还能用什么来通过它?(环境变量除外)最简单的解决方案似乎是使用管道,但这个最简单的解决方案并不容易。

我用 Perl 编程。

Gil*_*il' 27

进程参数对所有用户可见,但环境只对同一用户可见(至少在 Linux 上,我认为在每个现代 unix 变体上)。因此通过环境变量传递密码是安全的。如果有人可以读取您的环境变量,他们就可以像您一样执行进程,所以游戏已经结束了。

环境的内容有一些间接泄漏的风险,例如,如果您跑去ps调查某事并意外地将结果复制粘贴到公共场所,其中包括机密环境变量。另一个风险是您将环境变量传递给不需要它的程序(包括需要密码的进程的子进程),并且该程序公开其环境变量,因为它不希望它们是机密的。这些二次泄漏风险的严重程度取决于带有密码的进程的作用(运行多长时间?是否运行子进程?)。

通过将密码传递到并非设计为可窃听的通道(例如管道),可以更轻松地确保密码不会意外泄漏。这在发送端很容易做到。例如,如果你在 shell 变量中有密码,你可以这样做

echo "$password" | theprogram
Run Code Online (Sandbox Code Playgroud)

如果theprogram在其标准输入中需要密码。请注意,这是安全的,因为echo它是内置的;使用外部命令是不安全的,因为参数会在ps输出中公开。实现相同效果的另一种方法是使用 here 文档:

theprogram <<EOF
$password
EOF
Run Code Online (Sandbox Code Playgroud)

一些需要密码的程序可以被告知从特定的文件描述符中读取密码。如果您需要其他内容的标准输入,则可以使用标准输入以外的文件描述符。例如,使用gpg

get-encrypted-data | gpg --passphrase-fd 3 --decrypt … 3<<EOP >decrypted-data
$password
EOP
Run Code Online (Sandbox Code Playgroud)

如果不能告诉程序从文件描述符中读取,但可以告诉它从文件中读取,您可以通过使用像`/dev/fd/3 这样的文件名来告诉它从文件描述符中读取。

theprogram --password-from-file=/dev/fd/3 3<<EOF
$password
EOF
Run Code Online (Sandbox Code Playgroud)

在 ksh、bash 或 zsh 中,您可以通过进程替换更简洁地执行此操作。

theprogram --password-from-file=<(echo "$password")
Run Code Online (Sandbox Code Playgroud)


PSk*_*cik 10

而不是直接通过参数或环境变量传递密码

#!/bin/bash
#filename: passwd_receiver
echo "The password is: $1"
Run Code Online (Sandbox Code Playgroud)

使用相同的参数或环境变量来传递文件名

#!/bin/bash
#filename: passwd_receiver
echo "The password is: $(< "$1")"
Run Code Online (Sandbox Code Playgroud)

然后,你可以通过其中一个许可保护的常规文件(尽管这不会保护你从同一个用户下运行的其他进程),或/dev/stdin它(这AFAIK会保护你从同一个用户下运行的其他进程):

 echo PASSWORD | ./passwd_receiver /dev/stdin 
Run Code Online (Sandbox Code Playgroud)

如果你/dev/stdin在这里使用,它必须是一个 pipe。如果它是终端,则同一用户下运行的其他进程将可以读取它。

如果您已经需要将您的/dev/stdin用于其他用途,并且您在支持它的外壳上,则可以使用进程替换,这本质上等同于使用管道:

./passwd_receiver <(echo PASSWORD)
Run Code Online (Sandbox Code Playgroud)

命名管道 (FIFO) 可能看起来相同,但它们是可拦截的。

这些解决方案也不是完全安全的,但如果您不是在交换很多的内存受限系统上,它们可能足够接近。

理想情况下,您将这些文件(管道也是一个文件)读入标记为不可交换的mlock(2) 的内存中,这是密码处理程序(例如 gnupg)通常所做的。

笔记:

  1. 传递文件描述符编号理论上与传递文件名一样好,但文件名更实用,因为<()给你一个文件名,而不是一个文件描述符编号(并且coprocs 给你标记为FD_CLOEXEC 的文件描述符,这使得这些文件描述符在这种情况下无法使用)。

  2. 如果您在 Linux 系统上
    /proc/sys/kernel/yama/ptrace_scope设置为0,那么 AFAIK,没有防弹方法可以保护自己免受在同一用户下运行的其他进程的影响(他们可以使用 ptrace 附加到您的进程并读取您的内存)

  3. 如果您只需要让您的密码远离在不同(非root)用户下运行的进程,那么参数、环境变量、管道和受权限保护的文件都可以。


Jas*_*sen 7

不,环境变量也很容易读取,并泄漏到子进程。使用管道传递它。

  • 这个答案是错误的。其他用户无法读取环境变量。 (5认同)
  • “环境变量......泄漏给子进程” 这就是使用环境变量的全部意义所在。如果没有遗传,它们将毫无用处。“环境变量也很容易阅读”,不,它们不是。 (2认同)
  • 读取变量,取消设置。这并不难。你可以对管道使用相同的论点。如果管道未被读取,则将其传递给子进程,子进程可以读取它并获取密码。 (2认同)