Devo armazenar uma chave privada em um arquivo?

5

Eu tenho um aplicativo orientado por db que precisa se comunicar com outro servidor via ssh. O aplicativo da web pode gerar um par de chaves e dar ao usuário o pubkey, ou pode aceitar a chave privada não criptografada em um campo em um formulário da web. Em seguida, criptografa a chave com criptografia reversível e a armazena em seu banco de dados.

Quando o aplicativo da Web se comunica com o servidor ssh, eu preciso descriptografar a chave privada e fornecê-la para o ssh de uma forma ou de outra. Eu poderia criar um arquivo temporário seguro com mktemp , apontar ssh para ele e, em seguida, destruir o arquivo, mas isso é um trabalho extra que expõe a chave de uma nova maneira que parece não ser necessário. Eu olhei para man ssh , man ssh-agent e man ssh-add , mas parece não haver nenhuma maneira de usar a chave sem adicioná-la a um arquivo primeiro. O que estou perdendo?

    
por kojiro 14.02.2013 / 17:39

4 respostas

3

Se você quiser usar as ferramentas existentes, como ssh / ssh-agent , é necessário fornecer a chave como um arquivo.

Outra solução, talvez mais viável, é implementar diretamente um cliente ssh em seu aplicativo e depender de bibliotecas de terceiros, como JSch ou estenda ssh / ssh-agent diretamente para receber e descriptografar a chave do banco de dados.

    
por 14.02.2013 / 18:25
4

Os arquivos são a principal maneira de trocar dados entre aplicativos. Não precisa ser um arquivo de disco. Pode ser um arquivo em armazenamento temporário ou um pipe. Você pode alimentar um arquivo de chave para ssh-add em sua entrada padrão, contanto que o arquivo de chave não seja protegido por senha¹ (e como o arquivo de chave foi armazenado criptografado, não há razão para que ele seja protegido por senha) .

Como alternativa, não faça nada sofisticado e grave o arquivo em um sistema de arquivos com suporte a memória, como /run (ou /dev/shm ou /tmp ou qualquer que seja sua distribuição).

Como alternativa, mantenha o arquivo de chave privada sem criptografia externa, mas coloque uma senha nele. Use uma senha longa e gerada aleatoriamente e armazene essa senha no banco de dados.

¹ Experimentalmente, ssh-add bloqueia arquivos de chave protegidos por senha que não podem ser procurados, como pipes nomeados.

    
por 15.02.2013 / 00:29
3

Desculpe, não uma resposta, mas muito longa para um comentário, o que eu acho que está em vigor.

Importante é o que você está tentando alcançar armazenando a chave no banco de dados criptografado.

Um invasor que consiga acessar o arquivo de chave privada temporário também poderá ler a memória do processo do cliente ssh (e, portanto, acessar os dados-chave de qualquer forma), porque ambos os dados devem ter basicamente o mesmo acesso permissões - tentar esconder o arquivo não parece torná-lo mais seguro.

Se você estiver usando usuários diferentes para a conexão db, webapp e ssh, armazenando a chave no db, descriptografando-a no webapp e alimentando-a no ssh, você está abrindo vetores de ataque em potencial distribuindo a chave por todo o processo. Se você está usando apenas um usuário para todos eles (db, app, ssh), você não está ganhando nada, exceto pela complexidade do código.

A única vantagem parece ser uma transferência mais fácil do sistema para um host diferente e um ganho potencial, caso os dados do banco de dados sejam roubados, mas o webapp (que contém o algoritmo de descriptografia e a senha) não. Mas isso é provável?

Dito isto, se você quiser proteger a chave, você também pode usar a criptografia interna do ssh das chaves e carregá-las em um ssh-agent ao iniciar seu serviço (lembre-se de removê-lo quando ele parar!). Mas lembre-se novamente que o agente ssh mantém as chaves na memória não criptografadas, portanto, pode ser potencialmente lido. Mais uma vez: é este o problema que você está tentando resolver?

Se você só precisa proteger a comunicação entre duas máquinas, o stunnel pode ser de melhor qualidade que o ssh.

E, finalmente, para a pergunta: até onde OpenSSH ( portáteis ), escrever um patch simples que permita que ssh leia a chave de outro processo, pois sshd faz com a opção AuthorizedKeysCommand deve ser razoavelmente direta. / p>     

por 14.02.2013 / 18:31
2

Eu estava tentando resolver esse problema enquanto gerava os keypairs e os armazenava em um banco de dados com o Python. Abaixo estão alguns dos passos que acabei usando, começando ssh-agent e interagindo com ele. É em Python, mas presumivelmente você poderia traduzi-lo para qualquer outra coisa. Outra característica é que nenhum desses usa shell=True , então eles são mais seguros contra ataques de injeção.

import subprocess
import os
sockfile = '/some/place.sock'

agent = subprocess.Popen(['ssh-agent',
          '-D', # foreground mode
          '-a', sockfile, # bind address (socket file)
     ])
subprocess.check_call(['ssh-add', 
           '-D', # delete all identities from the agent
      ], 
      env={'SSH_AUTH_SOCK': sockfile},
)

Isso gera um ssh-agent apenas para o nosso programa e limpa (acredito que esteja carregando minhas chaves de usuário nele, não tenho certeza.) A variável de ambiente SSH_AUTH_SOCK normalmente definida por ssh-agent (mas que fizemos manualmente), estamos alimentando outros programas.

Em seguida, usamos ssh-add para alimentá-lo com a chave privada (aqui ele é armazenado em dr.private_key como uma string, mas eu preciso serializá-lo, então eu o codifico como ASCII).

adder = subprocess.Popen(['ssh-add', 
        '-', # read key from stdin
     ], 
     env={'SSH_AUTH_SOCK': sockfile}, 
     stdin=subprocess.PIPE,
)
adder.communicate(dr.private_key.encode('ascii'))
retval = adder.wait()
assert retval == 0 # added successfully

Agora, sempre que eu uso algum aplicativo que usa SSH, por exemplo Git, eu indico para usar o mesmo socket de agente SSH:

gitp = subprocess.Popen(
        ['git', '-C', os.path.abspath('../some-repo') ,'fetch'], 
        env={'SSH_AUTH_SOCK': sockfile}, 
        stdout=subprocess.PIPE, 
        stderr=subprocess.STDOUT,
    )
print(gitp.communicate()[0].decode('ascii'))

e funciona muito bem. O único "arquivo temporário" é o soquete usado por ssh-agent , mas é criado de modo que apenas o proprietário tenha permissões para ele e é removido quando você termina o agente.

    
por 10.03.2016 / 20:41