Como passar uma senha para um processo filho?

16

Passar uma senha na linha de comando (para um processo filho iniciado a partir do meu programa) é conhecido por ser inseguro (porque pode ser visto até mesmo por outros usuários com o comando ps). Não há problema em passá-lo como uma variável de ambiente?

O que mais posso usar para transmiti-lo? (Exceto da variável de ambiente) a solução mais fácil parece usar um pipe, mas essa solução mais fácil não é fácil.

Eu programo em Perl.

    
por porton 16.07.2016 / 13:12

4 respostas

22

Os argumentos do processo são visíveis para todos os usuários, mas o ambiente é visível apenas para o mesmo usuário ( pelo menos no Linux , e acho que em cada variante moderna do unix). Portanto, passar uma senha por meio de uma variável de ambiente é seguro. Se alguém pode ler suas variáveis de ambiente, elas podem executar processos como você, então já está em jogo.

O conteúdo do ambiente corre algum risco de vazamento indireto, por exemplo, se você executar ps para investigar algo e, acidentalmente, copiar e colar o resultado, incluindo variáveis de ambiente confidenciais em um local público. Outro risco é que você passe a variável de ambiente para um programa que não precise dela (incluindo filhos do processo que precisa da senha) e que o programa expõe suas variáveis de ambiente porque não esperava que fossem confidenciais. Quão ruim esses riscos de vazamento secundário depende do que o processo com a senha faz (quanto tempo ele é executado? Ele executa subprocessos?).

É mais fácil garantir que a senha não vaze acidentalmente passando-a por um canal que não foi projetado para ser interceptado, como um cano. Isso é muito fácil de fazer no lado do envio. Por exemplo, se você tiver a senha em uma variável do shell, você pode apenas fazer

echo "$password" | theprogram

se theprogram espera a senha em sua entrada padrão. Note que isto é seguro porque echo é um builtin; não seria seguro com um comando externo, pois o argumento seria exposto em ps output. Outra maneira de obter o mesmo efeito é com um documento aqui:

theprogram <<EOF
$password
EOF

Alguns programas que exigem uma senha podem ser instruídos a lê-la a partir de um descritor de arquivo específico. Você pode usar um descritor de arquivo diferente da entrada padrão se precisar de entrada padrão para outra coisa. Por exemplo, com gpg :

get-encrypted-data | gpg --passphrase-fd 3 --decrypt … 3<<EOP >decrypted-data
$password
EOP

Se o programa não puder ser instruído a ler de um descritor de arquivo, mas puder ser avisado para ler um arquivo, você poderá instruí-lo a ler um descritor de arquivo usando um nome de arquivo como '/ dev / fd / 3 .

theprogram --password-from-file=/dev/fd/3 3<<EOF
$password
EOF

Em ksh, bash ou zsh, você pode fazer isso de forma mais concisa através da substituição de processos.

theprogram --password-from-file=<(echo "$password")
    
por 17.07.2016 / 02:12
10

Em vez de passar a senha diretamente por meio de um argumento ou uma variável de ambiente

#!/bin/bash
#filename: passwd_receiver
echo "The password is: $1"

use o mesmo argumento ou variável de ambiente para passar um nome do arquivo :

#!/bin/bash
#filename: passwd_receiver
echo "The password is: $(< "$1")"

Em seguida, você pode transmitir um arquivo regular protegido por permissão (embora isso não proteja você de outros processos em execução com o mesmo usuário) ou /dev/stdin e pipe it in (que AFAIK irá protegê-lo de outros processos executados sob o mesmo usuário):

 echo PASSWORD | ./passwd_receiver /dev/stdin 

Se você usa /dev/stdin aqui, é imperativo que seja um canal . Se for um terminal, ele será legível por outros processos executados sob o mesmo usuário.

Se você já precisar usar seu /dev/stdin para outra coisa, poderá usar substituição de processo se estiver em um shell que ofereça suporte, o que é essencialmente equivalente ao uso de pipes:

./passwd_receiver <(echo PASSWORD)

Os pipes nomeados (FIFOs) podem parecer iguais, mas são interceptáveis.

Estas soluções não são perfeitamente seguras , mas podem estar próximas o suficiente, desde que você não esteja em um sistema com restrições de memória que troque muito.

O ideal seria que você lesse esses arquivos (o pipe também é um arquivo) na memória marcada com mlock (2) como não-expansível, que é o que os programas de manipulação de senhas, como o gnupg, geralmente fazem.

Notas:

  1. Passar números de filcripts é teoricamente bom como arquivo de nomes de arquivos, mas nomes de arquivos são mais práticos, porque <() dá a você um nome de arquivo, não um número de filodescriptor (e coproc s lhe dá filedescriptors marcados FD_CLOEXEC , o que torna esses descritores de arquivos inutilizáveis neste contexto).

  2. Se você estiver em um sistema Linux em que /proc/sys/kernel/yama/ptrace_scope esteja definido como 0 e, em seguida, AFAIK, não haverá uma maneira à prova de falhas de se proteger de outros processos executados sob o mesmo usuário (eles podem usar ptrace para anexar ao seu processo e ler sua memória)

  3. Se você só precisar manter sua senha longe de processos executados em usuários diferentes (não raiz), então todos os argumentos, variáveis de ambiente, canais e arquivos protegidos por permissão serão executados.

por 16.07.2016 / 19:49
7

Não, variáveis de ambiente são facilmente lidas e vazam para processos filhos. passá-lo usando um tubo.

    
por 16.07.2016 / 13:27
1

Se nada mais servir, considere o serviço de Retenção de Chaves do Linux (keyrings do kernel).

Comece em: security / keys.txt . Um dos keyrings padrão pode ser clonado entre os processos pai e filho.

Não é a solução mais simples, mas está lá e parece ser mantida & usado (também foi implicado em um bug Android no ano passado).

Eu não sei sobre seu status "político", mas eu tive uma necessidade semelhante, & começou a trabalhar em uma ligação Guile. Não encontrei suporte pré-existente Perl.

    
por 18.07.2016 / 04:19