Best practice per l'esecuzione di codice non affidabile

28

Ho un progetto in cui ho bisogno di consentire agli utenti di eseguire codice python arbitrario e non attendibile ( un po 'come questo ) contro il mio server. Sono abbastanza nuovo per Python e vorrei evitare di commettere errori che introducono buchi di sicurezza o altre vulnerabilità nel sistema. Ci sono buone pratiche disponibili, letture consigliate o altri suggerimenti che puoi darmi per rendere il mio servizio utilizzabile ma non abusivo?

Ecco cosa ho considerato finora:

  • Rimuovi __builtins__ dal contesto exec per vietare l'uso di pacchetti potenzialmente pericolosi come os . Gli utenti potranno utilizzare solo i pacchetti che fornisco loro.
  • Utilizza i thread per applicare un timeout ragionevole.
  • Vorrei limitare la quantità totale di memoria che può essere allocata all'interno del contesto exec , ma non sono sicuro che sia persino possibile.

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

  • Uso di ast.NodeVisitor per rilevare qualsiasi tentativo di accedere a oggetti non sicuri. Ma quali oggetti dovrei proibire?
  • Ricerca di eventuali caratteri di sottolineatura doppio nell'input. (meno elegante dell'opzione precedente).
  • Uso di PyPy o qualcosa di simile a sandbox del codice.

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

    
posta p.s.w.g 22.03.2013 - 22:01
fonte

5 risposte

27

Il sandboxing di Python è difficile . Python è intrinsecamente introspectable, a più livelli.

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

Ecco alcuni esempi di come trovare modi creativi per abbandonare le sandbox Python:

  • Ned Batchelder inizia con una dimostrazione di come % eval() pericoloso sia ; eval() è spesso usato per eseguire espressioni Python; come una sandbox primitiva e ingenua per one-liner.

    Ha quindi continuato a provare e applicare gli stessi principi a Python 3 , eventualmente riuscire a scoppiare con alcuni utili suggerimenti.

  • Pierre Bourdon utilizza tecniche simili a hack un sistema python su un hack-a-thon

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

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

Quindi, vuoi:

  • Controlla rigorosamente la compilazione di byte del codice Python, o almeno post-processa il bytecode per rimuovere qualsiasi accesso ai nomi che iniziano con caratteri di sottolineatura.

    Ciò richiede una conoscenza approfondita di come funziona l'interprete Python e di come è strutturato Bytecode Python. Gli oggetti codice sono nidificati; il codice byte di un modulo copre solo il livello più alto delle istruzioni, ogni funzione e classe è costituita dalla propria sequenza bytecode più metadati, contenenti altri oggetti bytecode per funzioni e classi annidate, per esempio.

  • Hai bisogno dei moduli whitelist che possono essere utilizzati. Con attenzione.

    Un modulo python contiene riferimenti a altri moduli. Se importi os , c'è un nome locale os nello spazio dei nomi del modulo che fa riferimento al modulo os . Questo può portare un determinato attaccante a moduli che possono aiutarli a uscire dalla sandbox. Il modulo pickle , ad esempio, ti consente di caricare oggetti di codice arbitrario, ad esempio, quindi se un percorso qualsiasi attraverso i moduli autorizzati conduce al modulo pickle , hai ancora un problema.

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

Dai un'occhiata a RestrictedPython , che tenta di darti il rigoroso controllo bytecode. RestrictedPython trasforma il codice Python in qualcosa che ti permette di controllare quali nomi, moduli e oggetti sono permessi in Python 2.3 fino a 2.7.

Se RestrictedPython è abbastanza sicuro per i tuoi scopi dipende dalle politiche che implementa. Non consentire l'accesso ai nomi che iniziano con un trattino basso e autorizzare rigorosamente la creazione di whitelist dei moduli sarebbe un inizio.

Secondo me, l'unica opzione veramente valida è quella di utilizzare una Virtual Machine separata, una senza accesso alla rete al mondo esterno che distruggi dopo ogni esecuzione. Invece, a ogni nuovo script viene assegnata una nuova VM. In questo modo, anche se il codice riesce a uscire dalla tua sandbox Python (che non è improbabile), tutto ciò a cui l'utente malintenzionato ha accesso è di breve durata e senza valore.

    
risposta data 22.03.2013 - 22:40
fonte
9

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

La best practice per l'esecuzione di codice non attendibile consiste nel separarla tramite una sandbox sistema . Per la massima sicurezza:

  • crea un contenitore con solo Python e le sue dipendenze e le dipendenze del contenitore
  • crea un contenitore senza tutti i dispositivi che non sono assolutamente necessari (cioè rete e archiviazione)
  • crea un contenitore con restrizioni sulla memoria e sull'utilizzo dei processi
  • ricrea il contenitore con ogni esecuzione (o almeno con ciascun utente unico e periodo di tempo massimo)
  • esegui come utente con il minimo privilegio necessario
  • esegui 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. È possibile ricostruire il filesystem di chroot con ogni chiamata, in particolare è paranoico. In genere, l'utente non è in grado di apportare modifiche al filesystem in cui viene eseguito il chroot.

    
risposta data 08.09.2013 - 20:07
fonte
3

Non c'è modo di farlo in sicurezza.

Se volessi fare qualcosa di simile in modo sicuro, dovresti iniziare avendo la tua implementazione di python che gira completamente ambiente controllato, preferibilmente eseguito nel browser degli utenti di sul tuo sistema. Si potrebbe iniziare con Jython (python per java) e impacchettarlo come applet java. Dal momento che sarebbe in esecuzione in Java sandbox, sulla macchina dell'utente, il sistema sarebbe ragionevolmente sicuro.

    
risposta data 22.03.2013 - 22:29
fonte
2

Come diceva Martijn sopra, questo è davvero, davvero difficile in Python. Sinceramente perché Python è così introspettabile, non penso sia possibile limitando le caratteristiche linguistiche. E se ottieni una sandbox che funziona per una versione di Python, c'è la possibilità che la prossima versione la infranga.

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

    
risposta data 08.09.2013 - 20:53
fonte
0

Finché le prestazioni non sono di enorme importanza per te, puoi sempre eseguirlo in Brython che lo colloca in modo efficace nella sandbox JavaScript

    
risposta data 09.06.2016 - 15:58
fonte

Leggi altre domande sui tag