Eu tenho um projeto em que preciso permitir que os usuários executem código python arbitrário e não confiável ( um pouco como este ) no meu servidor. Sou bastante novo em python e gostaria de evitar erros que introduzam falhas de segurança ou outras vulnerabilidades no sistema. Existem práticas recomendadas, leituras recomendadas ou outras dicas que você pode me dar para tornar meu serviço utilizável, mas não abusivo?
Aqui está o que eu considerei até agora:
- Remova
__builtins__
doexec
contexto para proibir o uso de pacotes potencialmente perigosos comoos
. Os usuários poderão usar apenas os pacotes que eu forneço a eles. - Use threads para impor um tempo limite razoável.
- Gostaria de limitar a quantidade total de memória que pode ser alocada dentro do
exec
contexto, mas não tenho certeza se é possível.
Existem algumas alternativas para uma sequência exec
, mas não tenho certeza qual delas seria útil aqui:
- Usando um
ast.NodeVisitor
para capturar qualquer tentativa de acessar objetos não seguros. Mas que objetos devo proibir? - Procurando por qualquer sublinhado duplo na entrada. (menos elegante que a opção acima).
- Usando
PyPy
ou algo semelhante à sandbox do código.
NOTA: Estou ciente de que há pelo menos um intérprete baseado em JavaScript. Isso não vai funcionar no meu cenário.
python
security
web-services
pswg
fonte
fonte
Respostas:
O sandbox do Python é difícil . Python é inerentemente introspectável, em vários níveis.
Isso também significa que você pode encontrar os métodos de fábrica para tipos específicos desses tipos e construir novos objetos de baixo nível, que serão executados diretamente pelo intérprete, sem limitação.
Aqui estão alguns exemplos de como encontrar maneiras criativas de sair das caixas de proteção do Python:
Ned Batchelder começa com uma demonstração de quão perigoso
eval()
é realmente ;eval()
é frequentemente usado para executar expressões Python; como uma caixa de areia primitiva e ingênua para one-liners.Ele então continuou a tentar aplicar os mesmos princípios ao Python 3 , eventualmente conseguindo romper com algumas dicas úteis.
Pierre Bourdon usa técnicas semelhantes para hackear um sistema python em um hack-a-thon
A idéia básica é sempre encontrar uma maneira de criar tipos básicos de Python; funções e classes e quebre o shell fazendo com que o interpretador Python execute bytecode arbitrário (não verificado!).
O mesmo e mais se aplicam à
exec
instrução (exec()
função no Python 3).Então, você quer:
Controle estritamente a compilação de bytes do código Python ou, pelo menos, pós-processe o bytecode para remover qualquer acesso aos nomes que começam com sublinhados.
Isso requer conhecimento profundo de como o interpretador Python funciona e como o bytecode do Python está estruturado. Objetos de código estão aninhados; o bytecode de um módulo cobre apenas o nível superior de instruções, cada função e classe consiste em sua própria sequência de bytecode mais metadados, contendo outros objetos de bytecode para funções e classes aninhadas, por exemplo.
Você precisa colocar os módulos na lista de permissões que podem ser usados. Cuidadosamente.
Um módulo python contém referências a outros módulos. Se você importar
os
, existe um nome localos
no namespace do módulo que se refere aoos
módulo. Isso pode levar um invasor determinado a módulos que podem ajudá-lo a sair da área restrita. Opickle
módulo, por exemplo, permite carregar objetos de código arbitrários, por exemplo, portanto, se algum caminho através dos módulos na lista de permissões levar aopickle
módulo, você ainda terá um problema.Você precisa limitar estritamente as cotas de tempo. Mesmo o código mais neutralizado ainda pode tentar executar para sempre, amarrando seus recursos.
Dê uma olhada no RestrictedPython , que tenta fornecer o controle estrito do bytecode.
RestrictedPython
transforma o código Python em algo que permite controlar quais nomes, módulos e objetos são permitidos no Python 2.3 até 2.7.Se
RestrictedPython
for suficientemente seguro para seus propósitos, depende das políticas que você implementa. Não permitir o acesso a nomes começando com um sublinhado e estritamente na lista de permissões dos módulos seria um começo.Na minha opinião, a única opção verdadeiramente robusta é usar uma máquina virtual separada, uma que não tenha acesso à rede para o mundo externo que você destrói após cada execução. Cada novo script recebe uma nova VM. Dessa forma, mesmo que o código consiga sair da sua caixa de proteção do Python (o que não é improvável), tudo o que o invasor obtém acesso é de curta duração e sem valor.
fonte
TL; DR Use um chroot / jail e execute como um usuário personalizado sem privilégios.
A melhor prática para executar código não confiável é segregá-lo por meio de uma caixa de proteção do sistema . Para maior segurança:
Você também segue práticas padrão para executar coisas com segurança em um chroot. Você pode reconstruir o sistema de arquivos do chroot a cada chamada também é particularmente paranóico. Normalmente, você apenas torna o usuário incapaz de fazer modificações no sistema de arquivos em que o chroot é executado.
fonte
Não há como você fazer isso com segurança.
Se você quiser fazer algo assim com segurança, terá que começar com sua própria implementação de python, que roda em um ambiente completamente controlado, de preferência no navegador do usuário, e não no sistema. Você pode começar com Jython (python para java) e empacotá-lo como um applet java. Como estaria em execução na sandbox java, na máquina do usuário, seu sistema estaria razoavelmente seguro.
fonte
Como Martijn disse acima, isso é realmente muito difícil em Python. Para ser franco, porque o Python é tão introspectável, não acho que seja possível limitando os recursos da linguagem. E se você tiver uma sandbox trabalhando para uma versão do Python, há uma chance de que a próxima versão a interrompa.
Eu daria uma olhada no PyPy em vez do CPython padrão. Em resumo, é uma implementação alternativa compatível do Python. Ele tem várias vantagens e recursos distintos, e um deles é o sandbox via substituição de chamadas do sistema, em vez de limitar os recursos de idioma.
fonte
Desde que o desempenho não seja extremamente importante para você, você sempre pode executá-lo no Brython, o que efetivamente o coloca na sandbox JavaScript
fonte