JavaScript Sandboxing: nascondi le variabili globali da un dato ambito
-
21-12-2019 - |
Domanda
Voglio creare un ambiente HTML + JS in cui l'utente può entrare ed eseguire il codice JavaScript arbitrario che verrà eseguito nel contesto dell'oggetto di prigione specificato. Ho impostato un Playground per illustrare ciò che ho finora .
Questo fa un lavoro un po 'decente:
- .
- Lavori di valutazione di base:
- .
- Input:
2 + 2
- Input:
- Uscita:
4
this
restituisce l'oggetto prigione
- .
- Input:
this
[object Object]
this.hello()
esegue il metodo previsto
- .
- Input:
this.hello()
hello world!
- .
- Input:
this.foo = function() { return 42; }
function () { return 42; }
this.foo()
42
- .
- Input:
hidden
ReferenceError: hidden is not defined
Tuttavia, non riesce completamente a nascondere le proprietà accessibili a livello globale, ad esempio window
o document
per l'utente:
- .
- Input:
window
- Uscita corrente:
[object Window]
- Uscita desiderata:
ReferenceError: window is not defined
La soluzione migliore che ho trovato finora è semplicemente riempire tutta la variabile globale che posso pensare con undefined
o null
direttamente nella dichiarazione dell'oggetto della prigione, come illustrato in versione aggiornata . In questo modo sembrano essere persi per sempre all'interno della portata della prigione e dell'utente non saranno in grado di accedervi. Le mie domande:
- .
- sono giusto? È abbastanza sicuro?
- C'è un modo migliore, cioè a veramente undefine roba globale in determinati ambito invece di riscriverle con alcuni valori segnapunti?
Soluzione
Se è lato client e puoi garantire un browser moderno, utilizzare I lavoratori Web invece; Sono molto più sicuri, e puoi anche interrompere infiniti loop di legare il thread principale e implementare timeout chiamando Worker#terminate
.
Avvia un nuovo lavoratore per ogni esecuzione:
var worker = new Worker('path/to/evaluator.js');
.
Ricevi messaggi dal lavoratore:
worker.onmessage = function (e) {
console.log(e.data);
};
.
Invia il codice da eseguire:
worker.postMessage(someCode);
.
Nel lavoratore, ascolta:
onmessage = function (e) {
postMessage(eval(e.data));
};
.
e assicurati di chiamare terminate
dopo aver ricevuto il messaggio, perché il lavoratore può chiamare postMessage
stesso. (Puoi impedirlo, ma non c'è davvero alcun punto.)
I lavoratori Web non hanno accesso a nulla nel contesto di esecuzione principale, funzionano su un altro thread, e sono implementati dal browser, quindi sono molto più sicuri della tipica sandbox eliminata-pericolosa-cose. < / P >.
loro fanno , tuttavia, hanno accesso a XMLHttpRequest
; Vedi È possibile sandbox javascript Nel browser? per altri approcci se questo è un problema.