Безопасно ли использовать 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это встроенная оболочка Это не появится в таблице процессов.
Кусалананда

Ответы:

15

Ваш код должен быть безопасным, так как echoон не будет отображаться в таблице процессов, поскольку это встроенная оболочка.

Вот альтернативное решение:

#!/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
Это умное решение, которое не нужно echoили printf, тем не менее, код немного неудобен для расшифровки
Nils Werner
@NilsWerner Добавил немного больше объяснений. Дайте мне знать, если вы хотите, чтобы я подробно остановился.
Кусалананда
1
Вы не должны полагаться на echoвстроенную оболочку. На большинстве снарядов это так, но абсолютно никаких требований к этому нет.
Остин Хеммельгарн
1
@Kusalananda Просто любопытно, есть ли эффективная разница между tee secret.txt > >(chpasswd)и tee secret.txt | chpasswd? Последнее кажется гораздо более распространенным, поэтому мне интересно, почему вы решили использовать замену процесса вместо простой трубы
Кристофер Шроба
1
@ChristopherShroba Нет другой причины, кроме того, что она похожа на код, который уже был в вопросе (используется подстановка процесса с помощью tee). Теперь, когда вы указали на это, я думаю, что на самом деле это изменится (выглядит лучше). Благодарю.
Кусалананда
8

echoСкорее всего, встроен в оболочку, поэтому он не будет отображаться 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.)

ilkkachu
источник
Ваше printfрешение не делать то , что мой исходный код делает: возвращает несколько строк для нескольких пользователей, но я ценю ваши замечания поhead urandom
Nils Вернер
@NilsWerner, ну, хотя расширение до нескольких пользователей очевидно. Но независимо от того, мы могли бы создать функцию для создания пар имя пользователя: пароль для нескольких пользователей за один раз. (см. редактирование)
ilkkachu
3
Вы не можете действительно полагаться на первые 10 «строк» ​​из урандома, содержащих достаточно символов, которые вы хотите. Просто запустите urandom прямо через tr.
Кусалананда
@ Кусалананда, ты имеешь в виду мой head -c 10 | base64трубопровод или Нильса head | tr? 10 «строк» ​​случайных байтов, скорее всего, будут сотнями байтов (учитывая, что только 1 из 256 будет новой строкой), хотя в теории это может быть ровно 10 байтов, но шансы на это совершенно незначительны. Точно так же при использовании base64, если случайные байты оказываются справедливыми \xff, то base64 будет просто цепочкой слэшей, но это тоже маловероятно. Если вы заботитесь, вы можете прочитать более 10 байтов, уменьшить вероятность этого, а затем сократить длину полученного результата.
ilkkachu
1
@ilkkachu Я имею в виду оба кода. Если вы читаете случайные байты и хотите что-то определенной длины после того, как отфильтровываете то, что вам не нужно, не отключайте источник данных, пока не убедитесь, что получили то, что вам нужно. Как вы говорите, очень маловероятно, что вы получите строку из десяти новых строк /dev/urandom, но риск не равен 0%.
Кусалананда