Есть ли способ передать конфиденциальные данные в bash, используя приглашение для любой команды?

40

Предположим, что я использовал sha1passдля генерации хеш-кода некоторого секретного пароля в командной строке. Я могу использовать sha1pass mysecretдля генерации хеша, mysecretно это имеет тот недостаток, который mysecretсейчас есть в истории bash. Есть ли способ выполнить конечную цель этой команды, избегая раскрытия mysecretв виде простого текста, возможно, с помощью passwdприглашения -style?

Я также заинтересован в обобщенном способе сделать это для передачи конфиденциальных данных любой команде. Метод будет меняться, когда конфиденциальные данные передаются в качестве аргумента (например, в sha1pass) или в STDIN какой-либо команде.

Есть ли способ сделать это?


Изменить : Этот вопрос привлек большое внимание, и было несколько хороших ответов, предложенных ниже. Резюме:

  • Согласно ответу @ Kusalananda , в идеале никогда бы не пришлось вводить пароль или секрет в качестве аргумента командной строки для утилиты. Это уязвимо в нескольких отношениях, как он его описал, и следует использовать более совершенную утилиту, способную принимать секретные данные на STDIN.
  • Ответ @ vfbsilva описывает, как предотвратить сохранение вещей в истории bash.
  • @ В ответе Джонатана описан совершенно хороший метод для достижения этой цели, если программа может хранить свои секретные данные в STDIN. Поэтому я решил принять этот ответ. sha1passв моем ОП был только пример, но обсуждение установило, что существуют лучшие инструменты, которые принимают данные о STDIN.
  • а @R .. отмечает в своем ответе , использование расширения команды на переменном не безопасно.

Итак, в целом, я принял ответ @ Jonathan, так как это лучшее решение, учитывая, что у вас есть хорошо продуманная и хорошо управляемая программа для работы. Хотя передача пароля или секрета в качестве аргумента командной строки принципиально небезопасна, другие ответы предоставляют способы смягчения простых проблем безопасности.

cemulate
источник
6
Мало того, что: любой человек на той же машине, у которого есть разрешение на просмотр запущенных процессов, может видеть, что sha1pass mysecretработает, и, следовательно, знать, что это mysecretтакое. (Это работает только в течение нескольких секунд , в то время как программа выполняется, конечно ...)
MathematicalOrchid
@MaturgicalOrchid Этого можно избежать, запустив частную виртуальную машину. Но это может быть слишком много работы для настройки, чтобы генерировать только один пароль ... :-)
Кусалананда
5
@Kusalananda Моя точка была более «никогда не ставить конфиденциальные данные в командной строке, даже если вы выяснить , как отключить историю команд» ...
MathematicalOrchid
2
Как вы знаете, SHA-1 не рекомендуется использовать для хеширования ключей или паролей уже довольно давно.
Дэвид Фёрстер
2
Обратите внимание, что если в системе запущен демон аудита, все команды и все аргументы всех пользователей регистрируются централизованно с правами root, поэтому любой, кто сможет получить доступ к этим журналам, увидит это.
Рэндалл

Ответы:

21

При использовании оболочки zshили bashиспользуйте опцию -s readвстроенной оболочки, чтобы прочитать строку из оконечного устройства, не повторяя ее.

IFS= read -rs VARIABLE < /dev/tty

Затем вы можете использовать некоторое перенаправление, чтобы использовать переменную в качестве стандартного ввода.

sha1pass <<<"$VARIABLE"

Если кто-нибудь запустится ps, он увидит только «sha1pass».

Это предполагает, что sha1passсчитывает пароль из stdin (в одной строке, игнорируя разделитель строк), когда не задано никакого аргумента.

Джонатан
источник
Я считаю, что мы установили, что sha1passне использует свой стандартный поток ввода.
Кусалананда
@Kusalananda Хорошо, но этот метод будет работать для программ, которые читают со стандартного ввода.
Джонатан
Итак, если утилита может сделать свой секретный ввод в STDIN, это надежное и безопасное решение с точки зрения безопасности?
Цемулировать
Я решил принять этот ответ, учитывая, что это лучшее решение, если у вас есть хорошо продуманная программа для работы. sha1passбыл просто примером в моем ОП, и явно не лучшим выбором для этого.
18:00
1
@cemulate, ... не безопасно в командной строке . В контексте heredoc или herestring (как в ответе здесь), он не подвергается ps, но может быть записан во временный файл - если кто-то хочет избежать этого, то sshpass < <(printf '%s\n' "$VARIABLE")может быть рассмотрен (потому что printfэто встроенная, а не внешняя команда, не передается execvи не доступна через ps).
Чарльз Даффи
36

В идеале, вы никогда не должны вводить открытый текстовый пароль в командной строке в качестве аргумента команды. Это делает пароль аргументом команды, а аргументы командной строки можно увидеть в таблице процессов, используя простые инструменты, такие как psили зарегистрированные в некоторых журналах аудита.

Сказав это, безусловно, есть способы скрыть фактический пароль от истории команд оболочки.

sha1pass "$( head -n 1 )"

Затем введите пароль и нажмите Enter. headКоманда , используемая здесь принимает ровно одну строку ввода и последний символ новой строки , что вы типа не будет частью данных , который передается sha1pass.

Чтобы символы не повторялись:

sha1pass "$( stty -echo; head -n 1; stty echo )"

Команда stty -echoотключает отображение введенных символов на терминале. Эхо затем восстанавливается с помощью stty echo.

Чтобы передать стандартный ввод, эту последнюю команду можно изменить (вы бы сделали это, если бы sha1passприняли данные на стандартном вводе, но похоже, что эта конкретная утилита игнорирует свой стандартный ввод):

{ stty -echo; head -n 1; stty echo; } | somecommand

Если вам требуется многострочный ввод (в приведенном выше примере предполагается, что должна быть пропущена одна строка без символа новой строки в конце), тогда замените всю headкоманду на catи завершите ввод (предполагая, что somecommandон читает до конца файла) с помощью Ctrl+D( следующее, Returnесли вы хотите включить символ ввода новой строки во ввод, или дважды, если нет).

Это будет работать независимо от того, какую оболочку вы используете (если это была оболочка типа Bourne или rc).

Некоторые оболочки могут быть сделаны, чтобы не сохранять введенные команды в своих файлах истории, если команде предшествует пробел. Обычно это связано с необходимостью установить HISTCONTROLзначение ignorespace. Это поддерживается по крайней мере bashи kshв OpenBSD, но не, например, ksh93или dash. zshпользователи могут использовать эту histignorespaceопцию или их HISTORY_IGNOREпеременную для определения шаблона, который следует игнорировать.

В оболочках, которые поддерживают чтение readбез вывода символов на терминал, вы также можете использовать

IFS= read -rs password     # -s turns off echoing in bash or zsh
                           # -r for reading backslashes as-is,
                           # IFS= to preserve leading and trailing blanks
sha1pass "$password"

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

Если утилита читает из стандартного ввода, и если оболочка поддерживает «here-строки», вышеприведенное можно изменить на

IFS= read -rs password
somecommand <<<"$password"

Сводка комментариев ниже:

  • Выполнение команды с паролем, заданным в командной строке, что делают все вышеперечисленные команды, кроме той, которая передает данные в команду, потенциально сделает пароль видимым для всех, кто работает psодновременно. Однако ни одна из приведенных выше команд не сохранит введенный пароль в файле истории оболочки, если он выполняется из интерактивной оболочки.

  • Программы с хорошим поведением, которые считывают пароли в виде открытого текста, делают это, считывая данные из стандартного ввода, из файла или непосредственно из терминала.

  • sha1pass Для этого требуется пароль в командной строке, либо введенный напрямую, либо с использованием какой-либо формы подстановки команд.

  • Если это вообще возможно, используйте другой инструмент.

Кусалананда
источник
11
Это неверно Результат расширения команды $(...)будет частью командной строки и будет виден в psвыходных данных, за исключением системы с усиленной / proc.
R ..
3
@Kusalananda, даже перезаписывая argv после того, как вы начали, оставляет уязвимое окно до того, как произойдет перезапись; это смягчение, а не исправление.
Чарльз Даффи
5
@Kusalananda, ни одна хорошо продуманная программа для хеширования паролей не потребует ввода в командной строке, поэтому условное условие - это, в основном, заданное значение, а если нет , следует выбрать другой инструмент.
Чарльз Даффи
4
@CharlesDuffy: инструмент здесь кажется принципиально сломанным. sha1passrun без пароля в командной строке, кажется, производит вывод, ничего не читая ... Так что OP должен выбрать другой инструмент.
R ..
8
Этот ответ небезопасен с точки зрения безопасности, и единственное преимущество состоит в том, что пароль не отображается в истории оболочки, но это преимущество легче реализовать, включив пробел перед командой
Ferrybig
25

Если вы установите HISTCONTROLтак:

HISTCONTROL=ignorespace

и запустите команду с пробелом:

~$  mycommand

это не будет сохранено в истории.

vfbsilva
источник
10

Передайте конфиденциальные данные через канал или здесь-документ:

command_with_secret_output | command_with_secret_input

или:

command_with_secret_input <<EOF
$secret
EOF

Хорошо, когда секреты хранятся в (неэкспортируемых) переменных оболочки, но вы никогда не сможете использовать эти переменные в командной строке, только в документах here и внутри оболочки.

Как отметил Кусалананда в комментарии, если вы вводите команды в интерактивной оболочке, строки, которые вы вводите для документа здесь, будут сохранены в истории оболочки, поэтому вводить пароль там небезопасно, но он все равно должен быть безопасно использовать переменные оболочки, содержащие секреты; история будет содержать текст, $secretа не что-либо $secretрасширенное до.

Использование расширений команд небезопасно :

command_with_secret_input "$(command_with_secret_output)"

потому что вывод будет включен в командную строку и виден в psвыводе (или при чтении вручную из / proc), за исключением систем с усиленной / proc.

Назначение переменной тоже хорошо:

secret=$(command_with_secret_output)
Р..
источник
То, что я ищу, это фактическая команда, command_with_secret_outputкоторая позволяет мне печатать секретный вывод. Существует ли такая команда, которую можно заменить здесь?
1918 года
Обратите внимание, что при вводе здесь документа в интерактивном bash сеансе документ будет сохранен в файле истории.
Кусалананда
@cemulate: просто используйте встроенную оболочку read, например read -r secret. Тогда ваш секрет в $secret. Вы можете запустить stty до / после него, чтобы скрыть ввод, если хотите.
R ..
3
@Kusalananda: sha1passкажется принципиально сломанным / непригодным / небезопасным, поскольку не может прочитать пароль из стандартного ввода или файла. Думаю, для решения проблемы нужна другая утилита.
R ..
1
@cemulate Ваш последний комментарий к R точно на месте. Вот почему это не поможет. read -rsвыполнит работу (если вы включите, -rчтобы иметь возможность иметь пароли с обратными слешами в них), но затем вы вернетесь к тому, чтобы потенциально показать пароль в списке процессов (и в зависимости от того, включен ли учет процессов и как он настроен , в журналах учета процессов, а также).
Кусалананда
6

Просто запишите значение в файл и передайте файл:

$ cat > mysecret
Big seecreeeet!
$ cat mysecret | sha1pass 

Я не уверен, как sha1passработает, если он может принять файл в качестве ввода, вы можете использовать sha1pass < mysecret. Если нет, использование catможет быть проблемой, так как он включает в себя последний перевод строки. Если это так, используйте (если headподдерживает -c):

head -c-1 mysecret | sha1pass 
Тердон
источник
2
Зачем записывать пароль на диск в вашем первом примере, когда вы можете просто сделать cat | sha1pass? cat mysecret | sha1passи sha1pass < mysecretимеют такое же поведение по отношению к последним переводам строки. catне добавляет новые строки. В любом случае, если sha1passподдерживается передача пароля через стандартный ввод, я ожидаю, что он сам по себе будет игнорировать последний перевод строки. Файлы со строками, которые не заканчиваются символами новой строки, в конце концов, являются неестественными в unix, поэтому было бы неудобно ожидать файл, который не завершается символом новой строки.
JoL
@JoL я) потому что я не думал об этом: / Но как это будет работать? cat | sha1passкажется, работает, sha1passпрежде чем дать мне шанс ввести любой ввод. II) Нет, конечно cat mysecret, не добавляет новую строку, я никогда не говорил, catдобавляет его, только то, что он включает его.
Terdon
Я вижу, но это не так, как < mysecretудаляет его тоже. :)
JoL
Не берите в голову. Теперь, когда я перечитал, я вижу, что вы сказали это, чтобы потом предложить head -c-1. Я думаю, я просто запутался, зачем использовать, cat mysecret | sha1passа потом предложу sha1pass < mysecret. Я предполагаю, что беспокойство заключается в том, что sha1pass может жаловаться на обычные файлы для stdin; Я не уверен почему.
JoL
@JoL это больше , потому что я никогда не использовал sha1passи не смог найти руководство или -hили любую другую форму документации в течение нескольких минут я провел поиск и поэтому не мог понять, если работает sha1pass fooлечения в fooкачестве входной строки или в качестве входного файла , Поэтому я дал варианты, чтобы иметь дело с каждой возможностью.
Terdon
1

Если то, что сделал Тердон, возможно, то это лучшее решение, проходящее через стандартный ввод. Осталась только одна проблема - он записал пароль на диск. Мы можем сделать это вместо этого:

stty -echo
echo -n "password: "
head -1 | sha1pass
stty echo

Как сказал Кусалананда, stty -echoто , что вы печатаете, не будет видно, пока вы не сделаете это stty echoснова. head -1получит одну строку из стандартного ввода и передать его sha1pass.

Йол
источник
0

я хотел бы использовать

sha1pass "$(cat)"

catбудет читать со стандартного ввода до EOF, что может быть вызвано нажатием Ctrl + D. Затем результат будет передан в качестве аргументаsha1pass

oktupol
источник
3
Ответ Р. объясняет, почему это небезопасно.
HVd