Sandboxing codice utente non affidabile fornito dall'utente in un'applicazione web

12

Sto cercando di creare un gioco di programmazione in cui i programmi forniti dagli utenti competono in simulazioni di battaglie, da utilizzare come strumento per insegnare e praticare la programmazione. (Sarà probabilmente una simulazione robot basata su turni, ma ai fini di questa domanda, potrebbe anche essere stata una partita a scacchi o dama.) Uno dei componenti principali dell'implementazione di questo gioco sarà quello di fornire un meccanismo per eseguire i generati dagli utenti codice contro i dati di gioco per determinare i movimenti del proprio bot.

So che il consiglio tipico è "Ovunque possibile, non eseguire codice non attendibile" e capisco da dove viene. Nel mio caso attuale, però, sarebbe la funzionalità principale dell'applicazione che vorrei realizzare, se possibile. So che dovrò prendere alcune precauzioni per garantire che il codice fornito dall'utente non causi danni. La configurazione ideale, da quello che posso dire, lo imporrebbe:

  • Il codice utente legge lo stato del gioco da STDIN
  • Il codice utente scrive generato sposta in STDOUT
  • Il codice utente è isolato dal sistema host
  • Il codice utente è isolato l'uno dall'altro
  • Il codice utente è limitato nelle risorse che può consumare (CPU, memoria, disco)
  • Il codice utente non può accedere alla rete

Il mio caso d'uso non sembra unico. Se mai, immagino che uno dei seguenti tipi di app abbia requisiti simili:

  • la maggior parte dei giochi di programmazione
  • giudici online di programmazione competitiva
  • "Prova il linguaggio di programmazione X"
  • concorsi AI di gioco

Tuttavia, ho cercato su Google, ma non sono riuscito a trovare alcuna implementazione di riferimento che sembrasse attendibile. La maggior parte delle app di cui sopra sono closed-source e forse per una buona ragione.

Considerati i requisiti, immagino di aver bisogno di una soluzione di isolamento / virtualizzazione / containerizzazione, anche se onestamente non sono sicuro di quale fornire le garanzie necessarie.

Quali sono le migliori pratiche attuali in merito al sandboxing per il codice fornito dall'utente? Qualcuno ha qualche informazione o riferimento a fonti affidabili?

    
posta Ming 07.07.2015 - 05:14
fonte

5 risposte

2

Tornando a questa domanda con un po 'di ritardo ... presumo che il codice che ricevi sia eseguito dal client nel suo interprete Javascript, e ad un certo punto inviato e interpretato sul server per la convalida.

Hai più problemi:

  1. vuoi assicurarti che il codice eseguito per un giocatore non possa influenzare negativamente un altro giocatore
  2. si desidera garantire che il codice che si esegue non consenta l'escalation dei privilegi a livello di sistema operativo
  3. bonus opzionale: vuoi sapere quando qualcosa è andato storto durante l'esecuzione del codice client

Disinfetta l'input

Per prima cosa: ricorda di inserire nella white-list gli input che ricevi dai tuoi clienti. Devono avere una lunghezza e un formato conosciuti. Utilizza un formato agnostico per la piattaforma per archiviare i dati che ricevi, che specifica le lunghezze e i tipi di tutte le variabili scambiate.

Isola i client

Devi quindi assicurarti che il calcolo di qualsiasi input possa portare a un risultato corretto, o al fallimento del calcolo senza influenzare il sistema operativo o altri calcoli concorrenti. Ciò significa che ogni input viene elaborato nel proprio thread / processo contenuto. Il tuo server Web potrebbe inoltrare l'input a un demone personalizzato che genera un processo sandbox per client e lo alimenta come input.

Potresti anche usare qualcosa come Cuneo per compartimentare in modo diretto e sicuro un singolo server. Capsicum potrebbe anche essere un'opzione.

Anche se hai scelto di utilizzare un singolo interprete Javascript per eseguire il codice JS scritto dai tuoi clienti non attendibili, presto avrai gli strumenti appropriati per garantire l'isolamento dal COWL (un meccanismo di confinamento che implementa con successo non interferenze per il codice JS) viene standardizzato dal W3C.

Proteggi il sistema operativo

In qualsiasi modo, devi semplicemente assicurarti che i processi che eseguono il tuo codice siano:

  • non eseguito da root / con funzionalità equivalenti a root
  • contenuto in un cgroup per abilitare le limitazioni della QoS su CPU, memoria, disco e larghezza di banda della rete (penso che quest'ultimo possa richiedere spazi dei nomi di rete)
  • contenuto in uno spazio dei nomi utente

Conoscere il risultato del calcolo è affidabile

Segui un corso sulla sicurezza basata sulla lingua :-) Questo è un obiettivo molto difficile in genere e richiede molte ipotesi sulla lingua e sulle proprietà di sicurezza che desideri garantire.

Buona fortuna!

    
risposta data 04.11.2015 - 18:21
fonte
0

Poiché una maggioranza (più del 50%) delle applicazioni web è costruita in Java, suppongo che stiate per distribuire un'applicazione web basata su Java.

Potresti prendere i file jar dagli studenti partecipanti e innanzitutto disinfettarli per malware ben noti per rimuovere le più ovvie fonti di problemi.

Potresti definire una classe di interfaccia sulla quale dovrebbe essere istanziato tutto il codice inviato. Questo potrebbe limitare il set di funzioni esposte all'ambiente di gioco, ad esempio getGameState (), calculateMove (), ecc. Il motore di gioco eseguirà questi metodi per ogni partecipante nella sequenza richiesta secondo le regole del gioco.

È necessario limitare il codice definendo un SecurityManager personalizzato con uno specifico ClassLoader per limitare le azioni nel dominio di sicurezza del partecipante. Ciò ti consentirà di applicare una politica di sicurezza personalizzata in modo molto flessibile.

Potresti prendere in considerazione l'applicazione delle seguenti autorizzazioni di accesso:

  1. Disattiva tutti gli accessi al filesystem.
  2. Consentire l'accesso riflessivo solo alle proprie classi.
  3. Rifiuta le chiamate di sistema pericolose come load (), loadLibrary (), gc (), setSecurityManager (), console (), ecc.
  4. Disattiva tutti gli accessi alla rete.
  5. Disattiva la creazione di nuovi thread.

Inoltre, prendere in considerazione il monitoraggio dell'allocazione della memoria e l'utilizzo del processore per il codice eseguito. Potresti estenderlo a qualsiasi risorsa disponibile sul server delle app.

Per scoraggiare gli studenti maliziosi o disattenti, puoi pubblicare metriche come il consumo di memoria e l'utilizzo del processore per le loro presentazioni. Potresti anche penalizzare i consumatori di risorse pesanti riducendo le loro classifiche in modo che gli studenti siano incoraggiati ad essere più cauti ed economici nell'uso delle risorse informatiche.

    
risposta data 16.08.2016 - 17:53
fonte
0

Hai considerato l'utilizzo di JavaScript e Google Caja ?

The Caja Compiler is a tool for making third party HTML, CSS and JavaScript safe to embed in your website. It enables rich interaction between the embedding page and the embedded applications. Caja uses an object-capability security model to allow for a wide range of flexible security policies, so that your website can effectively control what embedded third party code can do with user data.

The Caja Compiler supports most HTML and CSS and the recently standardized "strict mode" JavaScript version of JavaScript -- even on older browsers that do not support strict mode. It allows third party code to use new JavaScript features on older browsers that do not support them.

    
risposta data 21.08.2016 - 05:23
fonte
-2

Quindi molte persone stanno dicendo di sanitizzare l'input ( ottima risposta qui ), ma un ottimo approccio per questo sarebbe in lista bianca / lista nera e fare corrispondenze stringa .

Blacklist:
Se una qualsiasi parte della stringa contiene qualcosa di noto come "cattivo" e confrontato con un elenco che può essere aggiornato in remoto (ad esempio, un json di stringhe note in cattivi comandi che possono essere aggiornati da un repository e aggiunti troppo nel tempo), quindi puoi semplicemente combaciare con quello, e se soddisfa i requisiti di sicurezza vai avanti ed eseguilo.

Whitelist:
Ciò comporta anche l'aggiunta della funzionalità di utilizzare la corrispondenza delle stringhe per chiamare le routine predefinite che tu stesso hai scritto per creare il tuo set di istruzioni semplificato da utilizzare per i giocatori in modo che non possano nemmeno tentare di fare qualcosa di male. Ora tutto ciò che devi fare è scansionare e vedere che contiene solo i tuoi pattern pre approvati (di nuovo può essere aggiornato da remoto da qualche tipo di repository) e se contiene qualcos'altro, basta inviare un errore indicando un codice errato.

Svantaggi:

  • Manutenzione degli elenchi in modo tempestivo
  • Non renderlo troppo semplice
  • La maggior parte del tempo e la potenza saranno utilizzati per elaborare i comandi

Vantaggi:

  • L'hai definito
  • È possibile inviare l'input da disinfettare su un'altra macchina (se la macchina risponde in modo corretto e preformattato [conteggio esplicito dei caratteri, dimensione del pacchetto e modello], fidarsi dell'input ed eseguirlo)
  • Puoi rendere il gioco molto più semplice

Quindi, se mantieni il tuo sistema al sicuro, la corrispondenza delle stringhe potrebbe rendere più semplice la tua sicurezza poiché lo stai già facendo per disinfettare l'input.

    
risposta data 02.05.2016 - 23:06
fonte
-3

Esistono diverse sandbox integrate nel software più diffuso (motori antivirus, Adobe Reader, Java ecc.). Ciò che tutti questi programmi hanno in comune è che tutte le loro sandbox erano già state compromesse in passato.

Non è sufficiente scrivere solo sandbox, dato che qualcuno troverà il modo di evaderlo.

Quello che devi fare è scrivere un'implementazione completa della macchina virtuale. O semplicemente è lo stack di esecuzione, dato che puoi prendere un eccellente interprete LUA per l'analisi del linguaggio, la tokenizzazione e così via.

Ovviamente lo scopo di scrivere il proprio stack di esecuzione VM è consentire l'esecuzione completamente controllata dei programmi utente. Hai bisogno solo di un qualche sottoinsieme del linguaggio LUA, quindi dovrebbe essere facile eseguire tutto in modo controller - usando le variabili locali, senza alcuna interazione di rete / disco.

Qui hai un manuale per l'inizio:

link

Buona fortuna!

    
risposta data 07.07.2015 - 09:48
fonte

Leggi altre domande sui tag