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

36

Suponha que eu estivesse usando sha1pass para gerar um hash de alguma senha confidencial na linha de comando. Eu posso usar sha1pass mysecret para gerar um hash de mysecret , mas isso tem a desvantagem de que mysecret está agora no histórico do bash. Existe uma maneira de realizar o objetivo final desse comando, evitando ao mesmo tempo revelar mysecret no texto simples, talvez usando um prompt passwd -style?

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 forem passados como um argumento (como em sha1pass ) ou em STDIN para algum comando.

Existe uma maneira de realizar isso?

Editar : Esta questão atraiu muita atenção e tem havido várias boas respostas abaixo. Um resumo é:

  • De acordo com a resposta do @ Kusalananda , o ideal é nunca ter que dar uma senha ou segredo como um comando. argumento de linha para um utilitário. Isso é vulnerável de várias maneiras, conforme descrito por ele, e deve-se usar um utilitário melhor projetado que seja capaz de obter a entrada secreta em STDIN
  • A resposta do @ vfbsilva descreve como evitar que as coisas sejam armazenadas no histórico do bash
  • A resposta de @ Jonathan descreve um método perfeitamente bom para realizar isso, desde que o programa possa obter seus dados secretos no STDIN. Como tal, decidi aceitar esta resposta. sha1pass no meu OP foi apenas um exemplo, mas a discussão estabeleceu que existem ferramentas melhores que levam dados sobre STDIN.
  • como @R .. anotações em sua resposta , o uso da expansão de comando em uma variável não é segura.

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

    
por cemulate 23.04.2018 / 16:42

7 respostas

17

Se estiver usando o shell zsh ou bash , use a opção -s para o shell read incorporado para ler uma linha do dispositivo terminal sem que ele seja ecoado.

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á será "sha1pass".

Isso assume que sha1pass lê a senha de stdin (em uma linha, ignorando o delimitador de linha) quando não recebe nenhum argumento.

    
por 23.04.2018 / 21:37
35

O ideal é que você nunca digite uma senha de texto não criptografado na linha de comando como um 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 ps ou conectados a alguns logs de auditoria.

Dito isto, há certamente maneiras de esconder a senha real do histórico de comandos do shell.

sha1pass "$( head -n 1 )"

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

Para evitar que os caracteres ecoem:

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

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

Para passar na entrada padrão, esse último comando poderia ser alterado (você teria feito isso se sha1pass aceitasse dados na entrada padrão, mas aparecesse como se este utilitário específico estivesse ignorando sua entrada padrão):

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

Se você precisar de entrada de várias linhas (o acima pressupõe que uma única linha deve ser passada, sem caractere de nova linha no final), substitua o comando head inteiro por cat e termine a entrada (assumindo somecommand lê até o fim do arquivo) com Ctrl + D (seguindo Return se você quiser incluir um caractere de nova linha na entrada, ou duas vezes se não). / p>

Isso funcionaria independentemente do shell que você estava usando (desde que fosse um shell tipo Bourne ou rc).

Alguns shells podem ser criados para não salvar os comandos digitados em seus arquivos de histórico se o comando for precedido por um espaço. Isso geralmente envolve ter que definir HISTCONTROL para o valor ignorespace . Isto é suportado por pelo menos bash e ksh no OpenBSD, mas não por ex. ksh93 ou dash . zsh usuários podem usar a opção histignorespace ou sua variável HISTORY_IGNORE para definir um padrão a ser ignorado.

Em shells que suportam leitura com read sem ecoar caracteres para o 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 com a possibilidade de revelar a senha na tabela de processos.

Se o utilitário lê da entrada padrão, e se o shell suporta "aqui-strings", o acima pode ser alterado para

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

Resumo dos comentários abaixo:

  • Executar um comando com uma senha fornecida na linha de comando, que todos os comandos acima fazem, exceto aquele que envia os dados para o comando, tornará a senha visível para qualquer pessoa que esteja executando ps em o mesmo tempo. Nenhum dos comandos acima, no entanto, 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 simples fazem isso lendo suas entradas padrão, de 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 for possível, use outra ferramenta.

por 23.04.2018 / 17:12
24

Se você definir HISTCONTROL da seguinte forma:

HISTCONTROL=ignorespace

e inicie o comando com um espaço:

~$  mycommand

não será armazenado no histórico.

    
por 23.04.2018 / 16:59
9

Transmita dados confidenciais por meio de um pipe ou do here-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 usar essas variáveis em linhas de comando, apenas aqui - documentos e partes internas do shell.

Como notado por Kusalananda em um comentário, se você está digitando comandos em um shell interativo, as linhas digitadas 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 shell contendo segredos; o histórico conterá o texto $secret em vez de qualquer $secret expandido para.

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 em ps output (ou leitura manual de / proc), exceto em sistemas com endurecimento / proc.

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

secret=$(command_with_secret_output)
    
por 23.04.2018 / 17:44
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 sha1pass funciona, se puder usar um arquivo como entrada, você pode usar sha1pass < mysecret . Caso contrário, usar cat pode ser um problema, pois inclui a nova linha final. Se esse for o caso, use (se o seu head suportar -c ):

head -c-1 mysecret | sha1pass 
    
por 23.04.2018 / 17:09
1

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

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

Como Kusalananda disse, stty -echo garante que o que você digita não seja visto até você voltar a stty echo . head -1 receberá uma linha da entrada padrão e passará para sha1pass .

    
por 23.04.2018 / 17:56
0

eu usaria

sha1pass "$(cat)"

cat leria de stdin até EOF , o que pode ser causado pressionando Ctrl + D. Então, o resultado seria passado como argumento para sha1pass

    
por 25.04.2018 / 11:23