Pergunta

Um aplicativo deseja analisar e "executar" um arquivo, e deseja afirmar que o arquivo é executável por motivos de segurança.

Um momento de momentos e você percebe que esse código inicial tem uma condição de corrida que torna o esquema de segurança ineficaz:

import os

class ExecutionError (Exception):
    pass

def execute_file(filepath):
    """Execute serialized command inside @filepath

    The file must be executable (comparable to a shell script)
    >>> execute_file(__file__)  # doctest: +ELLIPSIS
    Traceback (most recent call last):
        ...
    ExecutionError: ... (not executable)
    """
    if not os.path.exists(filepath):
        raise IOError('"%s" does not exist' % (filepath, ))
    if not os.access(filepath, os.X_OK):
        raise ExecutionError('No permission to run "%s" (not executable)' %
                filepath)

    data = open(filepath).read()

    print '"Dummy execute"'
    print data

A condição de corrida existe entre

os.access(filepath, os.X_OK)

e

data = open(filepath).read()

Como existe a possibilidade de o arquivo ser substituído por um arquivo não executável de conteúdo diferente entre essas duas chamadas do sistema.

A primeira solução que tenho é alterar a ordem das chamadas críticas (e pular a verificação de existência agora redundante):

fobj = open(filepath, "rb")
if not os.access(filepath, os.X_OK):
    raise ExecutionError('No permission to run "%s" (not executable)' %
            filepath)

data = fobj.read()

Isso resolve a condição de corrida? Como posso resolver isso corretamente?

Racionalidade do esquema de segurança, brevemente (pensei)

O arquivo poderá realizar comandos arbitrários dentro de seu ambiente, por isso é comparável a um script de shell.

Havia um orifício de segurança nos desktops gratuitos com arquivos .DESKTOP que definem aplicativos: o arquivo pode especificar qualquer executável com argumentos e pode escolher seu próprio ícone e nome. Portanto, um arquivo baixado aleatoriamente pode se esconder atrás de qualquer nome ou ícone e fazer qualquer coisa. Isso foi ruim.

Isso foi resolvido exigindo que os arquivos .DESKTOP tenham o conjunto de bits executáveis; caso contrário, eles não serão renderizados com nome/ícone, e a área de trabalho gratuita perguntará ao usuário se ele deseja iniciar o programa antes de iniciar.

Compare isso com o design muito bom do Mac OS X: "Este programa foi baixado da Web, você tem certeza de que deseja abri -lo?".

Então, em alegoria com isso, e o fato de você ter que ter que chmod +x scripts de shell que você baixar, pensei no design na pergunta acima.

Palavras de encerramento

Talvez em conclusão, talvez devêssemos simplificar: se o arquivo deve ser executável, faça -o executável e deixe o kernel executá -lo quando invocado pelo usuário. Delegação da tarefa para onde ela pertence.

Foi útil?

Solução

A executabilidade está anexada ao arquivo que você abre, não há nada que interrompa vários arquivos de apontar para o inode contendo os dados que você deseja ler. Em outras palavras, os mesmos dados podem ser legíveis a partir de um arquivo não executável em outras partes do mesmo sistema de arquivos. Além disso, mesmo após a abertura do arquivo, você não pode impedir que a executabilidade desse mesmo arquivo mude, ele pode até ser desvinculado.

O "melhor esforço" disponível para você, como eu vejo, seria fazer cheques usando os.fstat No arquivo aberto, e verifique o modo de proteção e o tempo de modificação antes e depois, mas, na melhor das hipóteses, isso reduzirá apenas a possibilidade de que as alterações não sejam detectadas enquanto você lê o arquivo.

Em seguidas pensamentos, se você é o criador original dos dados neste arquivo, considere escrever um inode que nunca está vinculado ao sistema de arquivos em primeiro lugar, esta uma técnica comum no compartilhamento de memória por meio de arquivos. Como alternativa, se os dados contidos devem eventualmente tornar público para outros usuários, você poderá usar o bloqueio de arquivos e, em seguida, estender progressivamente os bits de proteção aos usuários que o exigem.

Por fim, você deve garantir que usuários maliciosos simplesmente não tenham acesso de gravação ao arquivo.

Outras dicas

Você não pode resolver inteiramente essa condição de corrida - por exemplo, na versão em que você abre pela primeira vez e depois verifique as permissões, é possível que as permissões sejam alteradas logo após você abrir o arquivo e antes de alterar as permissões.

Se você pode mover atomicamente o arquivo para um diretório onde os bandidos em potencial não podem chegar, poderá ter certeza de que nada sobre o arquivo será alterado debaixo do seu nariz enquanto você estiver lidando com isso. Se os potenciais bandidos podem alcançar em toda parte, ou você não pode mover o arquivo para onde eles não podem alcançar, não há defesa.

BTW, não está claro para mim como esse esquema, mesmo que pudesse funcionar, realmente acrescentaria qualquer segurança - certamente se os bandidos pudessem colocar conteúdo envenenado no arquivo, não está além deles chmod +x isso também?

O melhor que você pode fazer é:

  • salve a permissão.
  • Altere -o para o seu próprio usuário exclusivo (algo com o nome do programa) e proíba outros de executá -lo.
  • Faça você verifica (na permissão salva, se necessário).
  • execute seu processo.
  • Volte a permissão para os salvos.

Obviamente, existem desvantagens, mas se o seu caso de uso for tão simples quanto você parece dizer, isso pode fazer o truque.

Você deve alterar a propriedade dos arquivos para que um invasor não possa acessá -lo "CHOW ROOT: root file_name". Faça um "chmod 700 file_name" para que nenhuma outra conta possa ler/gravar/executar o arquivo. Isso evita o problema de um TOCTOU juntos e é assim que as pessoas impedem que os arquivos sejam modificados por um invasor que possui uma conta de usuário no seu sistema.

Outra maneira de fazer isso é alterar o nome do arquivo para algo inesperado ou até copiar o arquivo inteiro - se não for muito grande - para um diretor temporário (criptografado, se necessário), faça você verificar e renomeie / copie o arquivo de volta.

Claro que é um processo muito pesado.

Mas você acaba com isso porque o sistema não foi definido para a segurança desde o início. Um programa seguro assinaria ou criptografaria dados que ele deseja manter em segurança. No seu caso, não é possível.

A menos que você realmente tenha criptografado pesado, não há maneira de garantir 100 segurança em uma máquina que você não controla.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top