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


18

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

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

我在Perl中编程。


2
为什么不容易?它不必是单独的/命名管道,只需常规的stdin / out就可以了...在任何语言中都不会造成太大麻烦。如果可以确保只有感兴趣的进程才能读取它,则可以将其放在纯配置文件中(这比听起来困难得多)。
弗罗斯特斯2013年

1
如果您不给孩子打电话给exec,您仍然有密码的副本,而无需执行任何操作。
James Youngman

Answers:


26

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

环境的内容可能会存在间接泄漏的风险,例如,如果您ps尝试调查某些内容,并且在公共场所意外地将结果(包括机密环境变量)粘贴-粘贴。另一个风险是,您将环境变量传递给不需要它的程序(包括需要密码的进程的子进程),并且该程序公开了它的环境变量,因为它不希望它们是机密的。这些二次泄漏的风险有多严重取决于密码处理的过程(运行多长时间?运行子流程吗?)。

通过使密码通过未设计为窃听的通道(例如管道),可以更轻松地确保密码不会意外泄漏。在发送方这很容易做到。例如,如果您在shell变量中输入了密码,则只需执行

echo "$password" | theprogram

如果theprogram期望在其标准输入上输入密码。注意,这是安全的,因为echo它是内置的。使用外部命令并不安全,因为该参数将在ps输出中公开。获得相同效果的另一种方法是使用here文档:

theprogram <<EOF
$password
EOF

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

get-encrypted-data | gpg --passphrase-fd 3 --decrypt … 3<<EOP >decrypted-data
$password
EOP

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

theprogram --password-from-file=/dev/fd/3 3<<EOF
$password
EOF

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

theprogram --password-from-file=<(echo "$password")

在Solaris 9和更早的版本上,/usr/ucb/pssetuid为root,因此可以读取和显示其他进程的环境变量-在Solaris 10中已将其删除,因此上述“其他现代Unix变体”的答案适用于2005年及以后的Solaris发行版。
alanc

@alanc确实,这些天我不认为Solaris <10是现代的。Solaris 9几乎与Windows XP一样古老!
吉尔斯(Gilles)“所以,别再邪恶了”

男:有天我也很难考虑的Solaris 10现代现在的Solaris 11已经走出超过5年,所以我完全理解并同意,但可悲的是知道有些人仍然可以运行Solaris 8或9
alanc

10

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

#!/bin/bash
#filename: passwd_receiver
echo "The password is: $1"

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

#!/bin/bash
#filename: passwd_receiver
echo "The password is: $(< "$1")"

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

 echo PASSWORD | ./passwd_receiver /dev/stdin 

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

如果您已经需要将其/dev/stdin用于其他用途,则可以在支持它的shell上使用进程替换,这实际上等效于使用管道:

./passwd_receiver <(echo PASSWORD)

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

这些解决方案也不是完全安全的,但是只要您不在内存频繁交换的内存受限系统上,它们可能就足够接近了。

理想情况下,您会将这些文件(管道也是文件)读入标记为mlock(2)的不可交换内存中,这就是gnupg等密码处理程序通常会执行的操作。

笔记:

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

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

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


7

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


2
“环境变量...泄漏到子进程”这就是使用环境变量的重点。如果不被继承,它们将毫无用处。“环境变量也很容易读取”,不,它们不是。
Patrick

2
读取变量,将其取消设置。不难 您可以对管道使用相同的参数。如果未读取管道,则将其传递给子进程,并且子进程可以读取它并获取密码。
Patrick

1
@Patrick解封环境变量的记录手段不一定从位置擦洗值,其中ps/proc可以看到它。
zwol

1
某些系统是否允许您读取任意进程的环境变量?我认为Linux不允许其他人拥有的进程使用Linux,如果您是同一用户,则ptrace()无论如何都可以只是目标并读取其内存。
ilkkachu

5
这个答案是错误的。其他用户无法读取环境变量。
吉尔斯(Gillles)“所以-不要再邪恶了”

1

如果没有其他合适的方法,请考虑使用Linux密钥保留服务(内核密钥环)。

从以下位置开始:security / keys.txt。可以在父进程和子进程之间克隆默认密钥环之一。

它不是最简单的解决方案,但是它已经存在并且似乎可以维护和使用(去年它也牵涉到一个Android错误中。)

我不知道它的“政治”地位,但我有类似的需求,并开始从事Guile装订工作。尚未遇到过Perl支持。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.