2009-02-12 16 views
29

Ho un file javascript che legge un altro file che potrebbe contenere frammenti javascript che devono essere eval() - ed. Si suppone che i frammenti di script siano conformi a un sottoinsieme rigoroso di javascript che limita ciò che possono fare e quali variabili possono cambiare, ma voglio sapere se c'è un modo per far rispettare ciò impedendo all'eval di vedere le variabili nello scope globale . Qualcosa di simile a quanto segue:Restrizione di eval() a un ambito ristretto

function safeEval(fragment) 
{ 
    var localVariable = g_Variable; 

    { 
     // do magic scoping here so that the eval fragment can see localVariable 
     // but not g_Variable or anything else outside function scope 

     eval(fragment); 
    } 
} 

Il codice attuale non ha bisogno di assomigliare a questo - sto aperto a qualsiasi e tutti i trucchi strani con chiusure, ecc, ma io voglio sapere se questo è ancora possibile.

+0

Non so se funzionerà per 'eval', ma si può provare a passare il suo contesto di esecuzione (oggetto di attivazione di google). – jfs

+0

Dai un'occhiata all'implementazione dojox.secure.sandbox. – jfs

+0

Ora, quello che probabilmente vuoi è un Web Worker. – bjb568

risposta

50

Risposta breve: No. Se è nell'ambito globale, è disponibile a tutto.

Risposta lunga: se siete eval() ing codice non attendibile che davvero vuole leggere o pasticciare con il vostro ambiente di esecuzione, sei fregato. Ma se si possiede e fiducia tutto il codice in esecuzione, tra cui quello di essere essa eval() Ed, è possibile falso sovrascrivendo il contesto di esecuzione:

function maskedEval(scr) 
{ 
    // set up an object to serve as the context for the code 
    // being evaluated. 
    var mask = {}; 
    // mask global properties 
    for (p in this) 
     mask[p] = undefined; 

    // execute script in private context 
    (new Function("with(this) { " + scr + "}")).call(mask); 
} 

Ancora una volta, devo sottolineare:

Questo servirà solo per proteggere codice attendibile dal contesto in cui viene eseguito. Se non ti fidi del codice, NON lo eval() (o passa al nuovo Function(), o usalo in qualsiasi altro modo che si comporta come eval()).

+0

C'è un piccolo trucco con l'approccio 'with' che mi ha morso prima. Le funzioni dichiarate all'interno del blocco with non hanno accesso alla destinazione dell'istruzione with. –

+0

Sì, mi aspetto che una funzione * dichiarazione * possa essere "issata" in quel caso - si vorrebbe attenersi alle espressioni. – Shog9

+0

dannazione .... non posso dire quanto sono felice: D questo è fantastico !! ora posso completare il mio motore di template ... devo testare di più, ma penso di aver già tutto ... dannazione ... questo è un uomo piuttosto figo ... sai ... per analizzare le espressioni caricate dal template era difficile , ma con questo è piuttosto facile: D Conoscete eventuali falle di sicurezza? non ho mai saputo questo "con (questo)" ... so che devo controllare vor keaywords, per rimuovere l'iniezione del male: D – Mephiztopheles

2

Non puoi limitare la portata delle eval

btw vedere this post

Ci può essere un altro modo per realizzare ciò che vuoi realizzare nel grande schema delle cose, ma non si può limitare la portata di eval in ogni modo. Potresti essere in grado di nascondere determinate variabili come variabili pseudo private in javascript, ma non penso che questo sia ciò che stai cercando.

2

Ecco un'idea. Che cosa succede se si è utilizzato un analizzatore statico (qualcosa che è possibile creare con esprima, ad esempio) per determinare quali variabili esterne vengono utilizzate dal codice eval'd e come alias. Per "codice esterno" intendo le variabili il codice eval'd utilizza ma non dichiara.Ecco un esempio:

eval(safeEval(
    "var x = window.theX;" 
    +"y = Math.random();" 
    +"eval('window.z = 500;');")) 

dove safeEval restituisce la stringa javascript modificato con un contesto che blocca l'accesso a variabili esterne:

";(function(y, Math, window) {" 
    +"var x = window.theX;" 
    +"y = Math.random();" 
    +"eval(safeEval('window.z = 500;');" 
"})();" 

ci sono un paio di cose che puoi fare ora con questo:

  • È possibile garantire che il codice eval'd non possa leggere i valori delle variabili esterne, né scrivere su di essi (passando undefined come argomenti della funzione, o non passando argomenti). O potresti semplicemente lanciare un'eccezione nei casi in cui le variabili non sono accessibili.
  • È inoltre garantire che le variabili create da eval non influenzano l'ambito circostante
  • Si potrebbe consentire eval per creare variabili intervenute nell'area circostante dichiarando le variabili al di fuori della chiusura anziché come funzione di parametri
  • Si potrebbe consentire accesso in sola lettura da copia valori delle variabili al di fuori e li utilizzano come argomenti alla funzione
  • Si potrebbe permettere lettura e scrittura a variabili specifiche dicendo safeEval di non alias quei nomi particolari
  • È possibile rilevare casi in cui la valutazione fa non modificare una particolare variabile e consentire che venga automaticamente escluso dall'essere alias (es. Matematica in questo caso, non viene modificata)
  • Si potrebbe dare l'eval un contesto in cui eseguire, passando valori degli argomenti che possono essere differente rispetto al contesto circostante
  • è possibile catturare cambiamenti di contesto da anche restituire gli argomenti della funzione dalla funzione in modo da poterli esaminare al di fuori dell'eval.

noti che l'utilizzo di eval è un caso speciale, dato che per sua natura, è efficace non può essere avvolto in un'altra funzione (che è il motivo per cui dobbiamo fare eval(safeEval(...))).

Naturalmente, fare tutto questo lavoro può rallentare il codice, ma ci sono certamente posti in cui il successo non conta. Spero che questo aiuti qualcuno. E se qualcuno crea una dimostrazione di concetto, mi piacerebbe vedere un link ad esso qui;)

1

Non utilizzare eval. Esiste un'alternativa, js.js: JS interpreter written in JS, in modo che sia possibile eseguire programmi JS in qualsiasi ambiente che si è riusciti a configurare. Ecco un esempio della sua API dalla pagina del progetto:

var jsObjs = JSJS.Init(); 
var rval = JSJS.EvaluateScript(jsObjs.cx, jsObjs.glob, "1 + 1"); 
var d = JSJS.ValueToNumber(jsObjs.cx, rval); 
window.alert(d); // 2 
JSJS.End(jsObjs); 

Niente di spaventoso, come puoi vedere.

+0

3MB e solo 594KB dopo la compressione gzip – prototype

+0

@ user645715 1) Provare a utilizzare Closure Compiler per comprimerlo ancora di più. 2) C'è un rallentamento di 200x, che è molto peggio del codice sorgente di 3MB. 3) Non c'è ancora altra soluzione. –

1

Simile allo script di spostamento di funzione dinamica in un approccio di blocco with sopra, questo consente di aggiungere pseudo-globali al codice che si desidera eseguire. Puoi "nascondere" cose specifiche aggiungendole al contesto.

function evalInContext(source, context) { 
    source = '(function(' + Object.keys(context).join(', ') + ') {' + source + '})'; 

    var compiled = eval(source); 

    return compiled.apply(context, values()); 

    // you likely don't need this - use underscore, jQuery, etc 
    function values() { 
     var result = []; 
     for (var property in context) 
      if (context.hasOwnProperty(property)) 
       result.push(context[property]); 
     return result; 
    } 
} 

Vedere http://jsfiddle.net/PRh8t/ per un esempio. Si noti che Object.keys non è supportato in tutti i browser.

0

Non eseguire codice di cui non ci si fida. I Globali saranno sempre accessibili. Se fai fidare del codice, è possibile eseguire con particolari variabili nel suo ambito di applicazione come segue:

(new Function("a", "b", "alert(a + b);"))(1, 2); 

questo equivale a:

(function (a, b) { 
    alert(a + b); 
})(1, 2); 
0

risposta Shog9 ♦ s 'è grande. Ma se il tuo codice è solo un'espressione, il codice verrà eseguito e non verrà restituito nulla. Per le espressioni, utilizzare

function evalInContext(context, js) { 

    return eval('with(context) { ' + js + ' }'); 

} 

Ecco come usarlo:

var obj = {key: true}; 

evalInContext(obj, 'key ? "YES" : "NO"'); 

Si tornerà "YES".

Se non siete sicuri se il codice da eseguire è espressioni o dichiarazioni, è possibile combinarli:

function evalInContext(context, js) { 

    var value; 

    try { 
    // for expressions 
    value = eval('with(context) { ' + js + ' }'); 
    } catch (e) { 
    if (e instanceof SyntaxError) { 
     try { 
     // for statements 
     value = (new Function('with(this) { ' + js + ' }')).call(context); 
     } catch (e) {} 
    } 
    } 

    return value; 
} 
Problemi correlati