Existe uma maneira de transmitir dados confidenciais no bash usando um prompt, para qualquer comando?

40

Suponha que eu estivesse usando sha1passpara gerar um hash de alguma senha confidencial na linha de comando. Eu posso usar sha1pass mysecretpara gerar um hash, mysecretmas isso tem a desvantagem que mysecretestá agora no histórico do bash. Existe uma maneira de atingir o objetivo final deste comando, evitando revelar mysecretem texto simples, talvez usando um passwdprompt de estilo?

Também estou interessado em uma maneira generalizada de fazer isso para passar dados confidenciais para qualquer comando. O método mudaria quando os dados confidenciais fossem passados ​​como um argumento (como em sha1pass) ou no STDIN para algum comando.

Existe uma maneira de conseguir isso?


Edit : Esta questão atraiu muita atenção e houve várias boas respostas oferecidas abaixo. Um resumo é:

  • De acordo com a resposta de @ Kusalananda , o ideal seria nunca dar uma senha ou segredo como argumento da linha de comando a um utilitário. Isso é vulnerável de várias maneiras, conforme descrito por ele, e deve-se usar um utilitário melhor projetado, capaz de receber informações secretas sobre o STDIN
  • A resposta de @ vfbsilva descreve como impedir que coisas sejam armazenadas no histórico do bash
  • A resposta de @ Jonathan descreve um método perfeitamente bom para fazer isso, desde que o programa possa levar seus dados secretos para o STDIN. Como tal, decidi aceitar esta resposta. sha1passno meu PO era apenas um exemplo, mas a discussão estabeleceu que existem melhores ferramentas que utilizam dados no STDIN.
  • como @R .. observa em sua resposta , o uso da expansão de comando em uma variável não é seguro.

Então, em resumo, aceitei a resposta do @ Jonathan, já que é a melhor solução, pois você tem um programa bem projetado e comportado para trabalhar. Embora passar uma senha ou segredo como argumento da linha de comando seja fundamentalmente inseguro, as outras respostas fornecem maneiras de atenuar os simples problemas de segurança.

cemitar
fonte
6
Não é só isso: qualquer pessoa na mesma máquina com permissão para listar processos em execução pode ver o que sha1pass mysecretestá sendo executado e, portanto, saber o que mysecreté. (Isso só funciona para os poucos segundos enquanto o programa está sendo executado, é claro ...)
MathematicalOrchid
@MathematicsOrchid Isso pode ser evitado executando em uma máquina virtual privada. Mas isso pode ser muito trabalho para configurar para gerar apenas uma única senha ... :-)
Kusalananda
5
@Kusalananda Meu ponto era mais "não nunca colocar dados sensíveis na linha de comando, mesmo se você descobrir como desativar o histórico de comando" ...
MathematicalOrchid
2
Só para você saber, o SHA-1 está obsoleto para hashes de chave ou senha desde há alguns anos.
David Foerster
2
Observe que, se o sistema estiver executando um daemon de auditoria, todos os comandos e argumentos de todos os usuários serão registrados centralmente pelo root, para que qualquer pessoa que possa acessar esses logs o veja.
Randall

Respostas:

20

Se estiver usando o zshou bashshell, use a opção -s no readshell interno para ler uma linha do dispositivo terminal sem que ele ecoe.

IFS= read -rs VARIABLE < /dev/tty

Então você pode usar algum redirecionamento sofisticado para usar a variável como stdin.

sha1pass <<<"$VARIABLE"

Se alguém executar ps, tudo o que verá é "sha1pass".

Isso pressupõe que sha1passlê a senha de stdin (em uma linha, ignorando o delimitador de linha) quando não recebe nenhum argumento.

Jonathan
fonte
Acredito que estabelecemos que sha1passnão usa seu fluxo de entrada padrão.
Kusalananda
@ Kusalananda Ok, mas esse método funcionará para programas que lêem do stdin.
24718 Jonathan
Portanto, supondo que o utilitário possa receber sua entrada secreta no STDIN, essa é uma solução segura e segura, em termos de segurança?
usar o seguinte código
Decidi aceitar essa resposta, já que é a melhor solução, pois você possui um programa bem projetado para trabalhar. sha1passfoi apenas um exemplo no meu OP e claramente não é a melhor opção para isso.
cemulate
11
@cemulate, ... não é seguro em uma linha de comando . No contexto de um heredoc ou herestring (como na resposta aqui), ele não é exposto ps, mas pode ser gravado em um arquivo temporário - se alguém quiser evitar isso, sshpass < <(printf '%s\n' "$VARIABLE")pode ser considerado (porque printfé um builtin, não um comando externo, não é passado execve acessível via ps).
Charles Duffy
35

Idealmente, você nunca digita uma senha de texto não criptografado na linha de comando como argumento para um comando. Isso faz da senha um argumento para o comando, e os argumentos da linha de comando podem ser vistos na tabela de processos, usando ferramentas simples como psou registradas em alguns logs de auditoria.

Dito isto, certamente existem maneiras de ocultar a senha real do histórico de comandos do shell.

sha1pass "$( head -n 1 )"

Em seguida, digite a senha e pressione Enter. O headcomando usado aqui aceita exatamente uma linha de entrada e a última nova linha que você digita não fará parte dos dados transmitidos sha1pass.

Para impedir que os caracteres ecoem:

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

O stty -echocomando desativa o eco dos caracteres digitados no terminal. O eco é então restaurado com stty echo.

Para passar a entrada padrão, esse último comando pode ser alterado (você o faria se os sha1passdados aceitos na entrada padrão, mas parece que esse utilitário em particular está ignorando sua entrada padrão):

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

Se você precisar de entrada com várias linhas (o que foi dito acima pressupõe que uma única linha deva ser transmitida, sem nenhum caractere de nova linha no final), substitua o headcomando inteiro por cate encerre a entrada (supondo que somecommandele leia até o final do arquivo) com Ctrl+D( a seguir, Returnse você deseja incluir um caractere de nova linha na entrada ou duas vezes, se não).

Isso funcionaria independentemente de qual shell você estivesse usando (desde que fosse um shell tipo Bourne ou rc).

Alguns shells podem ser feitos para não salvar os comandos digitados nos arquivos de histórico se o comando for precedido por um espaço. Isso geralmente envolve ter que definir HISTCONTROLo valor ignorespace. Isso é suportado pelo menos bashe kshno OpenBSD, mas não por exemplo ksh93ou dash. zshos usuários podem usar a histignorespaceopção ou sua HISTORY_IGNOREvariável para definir um padrão a ser ignorado.

Nas conchas que suportam a leitura readsem ecoar caracteres no terminal, você também pode usar

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"

mas isso obviamente ainda tem o mesmo problema em potencialmente revelar a senha na tabela de processos.

Se o utilitário ler da entrada padrão e se o shell suportar "here-strings", o acima poderá ser alterado para

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

Resumo dos comentários abaixo:

  • A execução de um comando com uma senha fornecida na linha de comando, como todos os comandos acima, exceto o que canaliza os dados para o comando, potencialmente tornará a senha visível para qualquer pessoa que esteja executando psao mesmo tempo. No entanto, nenhum dos comandos acima salvará a senha digitada no arquivo de histórico do shell se executada a partir de um shell interativo.

  • Programas bem comportados que leem senhas em texto não criptografado fazem isso lendo suas entradas padrão, um arquivo ou diretamente do terminal.

  • sha1pass requer a senha na linha de comando, digitada diretamente ou usando alguma forma de substituição de comando.

  • Se possível, use outra ferramenta.

Kusalananda
fonte
11
Isto está incorreto. O resultado da expansão de comando $(...)fará parte da linha de comando e será visível na pssaída, exceto em um sistema com / proc.
R ..
3
@Kusalananda, mesmo sobrescrevendo o argumento após o início, deixa uma janela vulnerável antes que a substituição ocorra; é uma mitigação, não uma correção.
22418 Charles Duffy
5
@Kusalananda, nenhum programa bem projetado para senhas de hash exige entrada na linha de comando, de modo que condicional é basicamente um dado - se não for , deve-se escolher uma ferramenta diferente.
22718 Charles Duffy
4
@CharlesDuffy: A ferramenta aqui parece fundamentalmente quebrada. sha1passexecutar sem senha na linha de comando parece produzir uma saída sem ler nada ... Portanto, o OP precisa escolher uma ferramenta diferente.
R ..
8
Essa resposta não é seguro a partir de uma perspectiva de segurança, ea única vantagem é que a senha não aparecer na história shell, mas essa vantagem é mais fácil de realizar através da inclusão de um espaço na frente do comando
Ferrybig
25

Se você definir HISTCONTROLassim:

HISTCONTROL=ignorespace

e inicie o comando com um espaço:

~$  mycommand

não será armazenado no histórico.

vfbsilva
fonte
10

Passe dados confidenciais por um canal ou aqui-doc:

command_with_secret_output | command_with_secret_input

ou:

command_with_secret_input <<EOF
$secret
EOF

É bom que os segredos estejam em variáveis ​​de shell (não exportadas), mas você nunca pode usá-las em linhas de comando, apenas em documentos aqui e em shell internals.

Como observado por Kusalananda em um comentário, se você estiver digitando comandos em um shell interativo, as linhas que você digitar para um documento aqui serão armazenadas no histórico do shell, portanto, não é seguro digitar uma senha lá, mas ainda deve ser seguro usar variáveis ​​de shell contendo segredos; a história conterá o texto $secrete não o que for $secretexpandido.

O uso de expansões de comando não é seguro :

command_with_secret_input "$(command_with_secret_output)"

porque a saída será incluída na linha de comando e visível na pssaída (ou leitura manual de / proc), exceto em sistemas com / proc reforçado.

A atribuição a uma variável também é aceitável:

secret=$(command_with_secret_output)
R ..
fonte
O que estou procurando é um comando real command_with_secret_outputque me permita digitar a saída secreta. Existe um comando desse tipo que poderia ser substituído aqui?
cemulate
Observe que digitar um documento aqui em uma bash sessão interativa salvará o documento no arquivo de histórico.
Kusalananda
@cemulate: Basta usar o shell embutido read, por exemplo read -r secret. Então seu segredo está aí $secret. Você pode executar stty antes / depois para ocultar a entrada, se quiser.
R ..
3
@ Kusalananda: sha1passparece fundamentalmente quebrado / inutilizável / inseguro, pois não pode ler a senha do stdin ou de um arquivo. Um utilitário diferente é necessário para resolver o problema, eu acho.
R ..
11
@cemulate Seu último comentário para R está exatamente no local. É por isso que não vai ajudar. read -rsvai fazer o trabalho (se você incluir -ra ser capaz de ter senhas com barras invertidas em-los), mas então você está de volta ao potencialmente mostrando a senha na lista de processos (e consoante o processo de contabilidade está ligado e como isso é configurado , também nos registros contábeis do processo).
Kusalananda
6

Basta escrever o valor em um arquivo e passar o arquivo:

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

Não sei ao certo como sha1passfunciona; se ele pode receber um arquivo como entrada, você pode usá-lo sha1pass < mysecret. Caso contrário, o uso catpode ser um problema, pois inclui a nova linha final. Se for esse o caso, use (se o seu headsuporte -c):

head -c-1 mysecret | sha1pass 
terdon
fonte
2
Por que escrever a senha em disco no seu primeiro exemplo, quando você pode fazer isso cat | sha1pass? cat mysecret | sha1passe sha1pass < mysecrettem o mesmo comportamento em relação às novas linhas finais. catnão adiciona novas linhas. De qualquer forma, se houver sha1passsuporte para passar a senha através da entrada padrão, eu esperaria que ela ignorasse a nova linha final sozinha. Arquivos com linhas que não são finalizadas por novas linhas não são naturais no unix, afinal, seria estranho esperar um arquivo que não seja finalizado por uma nova linha.
JOL
@JoL i) porque eu não tinha pensado nisso: / Mas como isso funcionaria? cat | sha1passparece funcionar sha1passantes de me dar uma chance de inserir qualquer entrada. ii) Não, é claro cat mysecretque não adiciona uma nova linha, eu nunca disse que a catadiciona, apenas que a inclui .
terdon
Entendo, mas também não é como < mysecretremove. :)
JoL 23/04/19
Deixa pra lá. Agora que reli, vejo que você disse isso para propor mais tarde head -c-1. Acho que fiquei confuso sobre o porquê de usar cat mysecret | sha1passe depois propor sha1pass < mysecret. Acho que a preocupação é que o sha1pass possa reclamar dos arquivos regulares do stdin; Não sei por que.
JOL
@JoL é mais porque eu nunca usei sha1pass e não consegui encontrar um manual ou -hqualquer outra forma de documentação nos poucos minutos que passei pesquisando e, portanto, não consegui descobrir se a execução é sha1pass footratada foocomo uma string de entrada ou como um arquivo de entrada . Por isso, dei opções para lidar com cada possibilidade.
terdon
1

Se o que o terdon fez é possível, essa é a melhor solução, passando pela entrada padrão. O único problema que resta é que ele escreveu a senha no disco. Em vez disso, podemos fazer isso:

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

Como Kusalananda disse, stty -echogarante que o que você digita não é visto até que você faça stty echonovamente. head -1obterá uma linha da entrada padrão e a passará para sha1pass.

JoL
fonte
0

eu usaria

sha1pass "$(cat)"

cat leria de stdin até EOF , o que pode ser causado pressionando Ctrl + D. Em seguida, o resultado seria passado como argumento parasha1pass

oktupol
fonte
3
A resposta de R .. explica por que isso não é seguro.
Hv