Best practice per l'esecuzione di codice non attendibile


31

Ho un progetto in cui devo consentire agli utenti di eseguire codice Python arbitrario e non attendibile ( un po 'come questo ) contro il mio server. Sono abbastanza nuovo su Python e vorrei evitare di commettere errori che introducano falle nella sicurezza o altre vulnerabilità nel sistema. Ci sono delle migliori pratiche disponibili, letture consigliate o altri suggerimenti che puoi darmi per rendere il mio servizio utilizzabile ma non abusabile?

Ecco cosa ho considerato finora:

  • Rimuovere __builtins__dal execcontesto per vietare l'uso di pacchetti potenzialmente pericolosi come os. Gli utenti potranno utilizzare solo i pacchetti che fornisco loro.
  • Utilizzare i thread per imporre un timeout ragionevole.
  • Vorrei limitare la quantità totale di memoria che può essere allocata nel execcontesto, ma non sono sicuro che sia possibile.

Ci sono alcune alternative a una scala exec, ma non sono sicuro di quale di questi sarebbe utile qui:

  • Usare un ast.NodeVisitorper catturare qualsiasi tentativo di accedere a oggetti non sicuri. Ma quali oggetti dovrei vietare?
  • Ricerca di eventuali sottolineature doppie nell'input. (meno grazioso dell'opzione sopra).
  • Utilizzando PyPyo qualcosa di simile a sandbox il codice.

NOTA: sono consapevole che esiste almeno un interprete basato su JavaScript. Questo non funzionerà nel mio scenario.



3
@MartijnPieters: eccellente. Probabilmente degno di una risposta, se riassumi ognuno.
Robert Harvey,

Considera anche: immondizia rimasta sul disco, rete (non consentire loro di inviare spam o altro), autorizzazioni ad altri file (lettura dei file). Anche espellere in while loop può distruggere la meccanica del CD ... Vorrei andare alla virtualizzazione (jail o qualche kvm che lo chiami) o almeno all'utente senza quasi privilegi. Imposta una buona quantità di memoria e una ragionevole quantità di memoria a vantaggio dei tuoi programmi.
kyticka,


1
Prova PyPy :> Sandboxing: PyPy offre la possibilità di eseguire codice non attendibile in modo completamente sicuro.
Vorac,

Risposte:


28

Il sandboxing in Python è difficile . Python è intrinsecamente introspettibile, a più livelli.

Ciò significa anche che puoi trovare i metodi di fabbrica per tipi specifici da quei tipi stessi e costruirne di nuovi oggetti di basso livello, che verranno eseguiti direttamente dall'interprete senza limitazioni.

Ecco alcuni esempi di come trovare modi creativi per uscire dai sandbox Python:

L'idea di base è sempre quella di trovare un modo per creare tipi Python di base; funzioni e classi e uscire dalla shell facendo in modo che l'interprete Python esegua un bytecode arbitrario (non controllato!).

Lo stesso e altro vale per l' execistruzione ( exec()funzione in Python 3).

Quindi, vuoi:

  • Controlla rigorosamente la compilazione dei byte del codice Python, o almeno post-elabora il bytecode per rimuovere qualsiasi accesso ai nomi che iniziano con i trattini bassi.

    Ciò richiede una conoscenza intima del funzionamento dell'interprete Python e della struttura del bytecode Python. Gli oggetti codice sono nidificati; il bytecode di un modulo copre solo il livello più alto di istruzioni, ogni funzione e classe è costituita dalla propria sequenza bytecode più metadati, contenenti altri oggetti bytecode per funzioni e classi nidificate.

  • Devi autorizzare inserire moduli che possono essere utilizzati. Accuratamente.

    Un modulo Python contiene riferimenti ad altri moduli. Se si importa os, c'è un nome locale osnel proprio spazio dei nomi del modulo che si riferisce al osmodulo. Ciò può condurre un determinato aggressore a moduli che possono aiutarlo a uscire dalla sandbox. Il picklemodulo, ad esempio, consente di caricare oggetti di codice arbitrari, ad esempio, quindi se qualsiasi percorso attraverso i moduli nella whitelist porta al picklemodulo, il problema persiste.

  • È necessario limitare rigorosamente le quote temporali. Anche il codice più castrato può ancora tentare di essere eseguito per sempre, vincolando le risorse.

Dai un'occhiata a RestrictedPython , che tenta di darti il ​​rigoroso controllo bytecode.RestrictedPythontrasforma il codice Python in qualcosa che ti consente di controllare quali nomi, moduli e oggetti sono ammessi in Python da 2.3 a 2.7.

Se RestrictedPython è abbastanza sicuro per i tuoi scopi dipende dalle politiche che implementi. Non consentire l'accesso ai nomi che iniziano con un carattere di sottolineatura e la whitelist rigorosa dei moduli sarebbe un inizio.

A mio avviso, l'unica opzione veramente robusta è quella di utilizzare una macchina virtuale separata, una senza accesso di rete al mondo esterno che si distrugge dopo ogni corsa. Ad ogni nuovo script viene invece assegnata una nuova VM. In questo modo, anche se il codice riesce a uscire dalla sandbox di Python (il che non è improbabile), tutto ciò a cui l'utente malintenzionato può accedere è di breve durata e senza valore.


10

TL; DR Utilizza un chroot / jail ed esegui come utente personalizzato senza privilegi.

La migliore pratica per l'esecuzione di codice non attendibile è quella di separarlo tramite un sandbox di sistema . Per la massima sicurezza:

  • crea un contenitore con solo Python e le sue dipendenze e le dipendenze del contenitore
  • creare un contenitore senza tutti i dispositivi che non sono assolutamente necessari (ad es. rete e archiviazione)
  • creare un contenitore con restrizioni sulla memoria e sull'utilizzo dei processi
  • ricreare il contenitore ad ogni esecuzione (o almeno con ciascun utente unico e periodo di tempo massimo)
  • eseguito come utente con il minor privilegio necessario
  • eseguito come utente che non dispone delle autorizzazioni per scrivere file

Segui anche le pratiche standard per eseguire le cose in modo sicuro in un chroot. Puoi ricostruire il filesystem del chroot anche con ogni chiamata è particolarmente paranoica. In genere, l'utente non è in grado di apportare modifiche al filesystem in cui viene eseguito chroot.


Questa è l'unica cosa in cui sarai anche lontanamente sicuro di averlo fatto bene: dagli il suo processo.
Michael Kohne,

3

Non è possibile farlo in modo sicuro.

Se volessi fare qualcosa del genere in modo sicuro, dovresti iniziare con la tua implementazione di Python che gira in un ambiente completamente controllato, preferibilmente nel browser degli utenti anziché sul tuo sistema. Potresti iniziare con Jython (python per Java) e impacchettarlo come applet Java. Dal momento che sarebbe in esecuzione nella sandbox java, sul computer dell'utente, il tuo sistema sarebbe ragionevolmente sicuro.


4
La questione della sicurezza era per il suo server, non per la macchina del client. I potenziali rischi per la sicurezza di Java, come quelli per qualsiasi altra tecnologia web, sono che il server potrebbe essere utilizzato per distribuire programmi pericolosi per il client.
colorato il

1
@grasGendarme proprio come i nuovi piani sugli incidenti aerei in realtà ti dicono molto su quanto siano rari; le storie sui buchi di sicurezza di Java ti dicono che Java è relativamente sicuro. Non avresti mai avuto una storia del genere su C perché la risposta che riceveresti sarebbe "beh, se lo fai farà tutto quello che vuole"
Richard Tingle

2

Come Martijn ha detto sopra, questo è davvero molto difficile in Python. Senza mezzi termini perché Python è così introspettibile, non penso che sia possibile limitando le funzionalità del linguaggio. E se ottieni un sandbox funzionante per una versione di Python, c'è la possibilità che la prossima versione lo rompa.

Darei un'occhiata a PyPy anziché a CPython standard. In breve, è un'implementazione alternativa conforme di Python. Presenta numerosi vantaggi e funzionalità distinte e uno di questi è il sandboxing tramite la sostituzione delle chiamate di sistema anziché la limitazione delle funzionalità del linguaggio.


0

Finché le prestazioni non sono estremamente importanti per te, puoi sempre eseguirle in Brython, che le inserisce efficacemente nella sandbox JavaScript

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.