使用echo将敏感数据传递到chpasswd是否安全?


17

我正在尝试使用批量设置一些用户帐户密码chpasswd。密码应随机生成并打印到stdout(我需要写下来或将它们放在密码存储区中),然后再传递到中chpasswd

天真的,我会这样

{
  echo student1:$(head /dev/urandom | tr -dc A-Za-z0-9 | head -c 13 ; echo '')
  echo student2:$(head /dev/urandom | tr -dc A-Za-z0-9 | head -c 13 ; echo '')
} | tee >(chpasswd)

但是,我担心将新密码作为命令行参数传递给echo,因为参数通常对中的其他用户可见ps -aux(尽管我从未看到中echo出现任何行ps)。

是否有其他方法可以在返回的密码前添加一个值,然后将其传递给chpasswd


6
echo是内置的Shell。它不会在过程表中显示。
库萨兰达

Answers:


15

您的代码应该是安全的,echo因为它是内置的shell ,因此不会出现在进程表中。

这是一个替代解决方案:

#!/bin/bash

n=20
paste -d : <( seq -f 'student%.0f' 1 "$n" ) \
           <( tr -cd 'A-Za-z0-9' </dev/urandom | fold -w 13 | head -n "$n" ) |
tee secret.txt | chpasswd

这将创建您的学生姓名和密码,n而无需在任何命令的任何命令行上传递任何密码。

paste实用程序将几个文件作为列粘合在一起,并在它们之间插入定界符。在这里,我们:用作分隔符,并给它两个“文件”(进程替换)。第一个包含seq创建20个学生用户名的命令的输出,第二个包含创建20个长度为13的随机字符串的管道的输出。

如果您已经有一个带有用户名的文件:

#!/bin/bash

n=$(wc -l <usernames.txt)

paste -d : usernames.txt \
           <( tr -cd 'A-Za-z0-9' </dev/urandom | fold -w 13 | head -n "$n" ) |
tee secret.txt | chpasswd

这些会将密码和用户名保存到文件中,secret.txt而不是在终端中显示生成的密码。


2
这并不需要一个聪明的解决方案echoprintf,但是代码是一个有点尴尬破译
尼尔斯·沃纳

@NilsWerner添加了更多解释。让我知道您是否想扩展我的一件事。
库萨兰达

1
但是,您不应依赖于echo内置shell。在大多数炮弹上都可以,但是绝对没有要求。
奥斯汀·海默加恩

1
@Kusalananda只是好奇,tee secret.txt > >(chpasswd)和之间有有效的区别tee secret.txt | chpasswd吗?后者似乎更常见,所以我想知道为什么您选择使用过程替代而不是普通管道
Christopher Shroba '18

1
@ChristopherShroba除了它与问题中已存在的代码相似(使用来代替tee)之外,没有其他原因。既然您已经指出了这一点,我想我实际上会对其进行更改(看起来更好)。谢谢。
库萨兰达

8

echo是很可能内置在shell中的,因此不会ps作为单独的进程出现。

但是您不需要使用命令替换,您只需将管道的输出直接传递给chpasswd

{  printf "%s:" "$username";
   head /dev/urandom | tr -dc A-Za-z0-9 | head -c 13 ; echo ''
} | chpasswd 

如果您希望一次运行更改多个密码chpasswd,那么重复重要部分应该很容易。或使其成为一个函数:

genpws() {
    for user in "$@"; do
        printf "%s:" "$user";
        head /dev/urandom | tr -dc A-Za-z0-9 | head -c 13
        echo
    done
}
genpws username1 username2... | chpasswd 

顺便说head /dev/urandom一句:感觉有点奇怪,因为urandom它不是面向行的。它可能会从中读取过多的字节,这将影响内核的可用熵概念,从而可能导致/dev/random阻塞。只是读取固定数量的数据,并使用类似的base64方法将随机字节转换为可打印字符(而不是仅仅丢掉大约3/4的字节),这样可能会更清洁。

这样的事情会给你大约。16个字符和数字:

head -c 12 /dev/urandom | base64 | tr -dc A-Za-z0-9 

(也就是说,输出中的+/字符的数量要少16个字符base64。每一个字符的可能性为1/32,因此,如果我正确使用了组合语言,则有99%的机会保留至少14个字符,并且99.99%的机会至少离开12。)


您的printf解决方案不执行我的原始代码所执行的操作:为多个用户名返回多行,但是我感谢您的发言head urandom
Nils Werner,

@NilsWerner,好吧,尽管我可以扩展到多个用户,但很明显。但是无论如何,我们可以创建一个函数,一次生成多个用户的username:password对。(请参阅编辑)
ilkkachu

3
您不能真正依靠urandom中包含所需字符的前10个“行”。而是直接通过tr运行urandom。
库萨兰达

@Kusalananda,您是说我的head -c 10 | base64管道,还是Nils的管道head | tr?10个“行”的随机字节很可能是数百个字节(假设256中只有1个行是换行符),尽管从理论上讲它可能恰好是10个字节,但是这种可能性完全可以忽略不计。类似地,在使用时base64,如果随机字节恰好是just \xff,那么base64只是一串斜杠,但这也不太可能。如果您愿意的话,您可以读取10个以上的字节,降低其几率,然后减少结果输出的长度。
ilkkachu

1
@ilkkachu我指的是两个代码。如果您读取随机字节,并且在过滤掉不需要的内容后想要特定长度的内容,那么请不要切断数据源,除非您确定已获得所需的内容。正如您所说,您不太可能从那里得到一串十个换行符/dev/urandom,但是风险不是0%。
库萨兰达
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.