Domanda

La funzione eval è un modo semplice e potente per generare dinamicamente codice, quindi quali sono gli avvertimenti?

È stato utile?

Soluzione

  1. Uso improprio di eval Apre il tuo codice per gli attacchi di iniezione

  2. Debug Può essere più impegnativo (nessun numero di riga, ecc.)

  3. il codice valutato viene eseguito più lentamente (nessuna possibilità di compilare/memorizzare nella cache il codice valutato)

Modificare:Come sottolinea @Jeff Walden nei commenti, il punto 3 è meno vero oggi di quanto lo fosse nel 2008.Tuttavia, sebbene possa verificarsi una certa memorizzazione nella cache degli script compilati, questa sarà limitata solo agli script che vengono ripetuti senza alcuna modifica.Uno scenario più probabile è che si stiano valutando script che hanno subito lievi modifiche ogni volta e come tali non possono essere memorizzati nella cache.Diciamo solo che ALCUNI codici valutati vengono eseguiti più lentamente.

Altri suggerimenti

eval non è sempre malvagio.Ci sono momenti in cui è perfettamente appropriato.

Tuttavia, eval è attualmente e storicamente ampiamente utilizzato da persone che non sanno cosa stanno facendo.Ciò include persone che scrivono tutorial JavaScript, sfortunatamente, e in alcuni casi ciò può effettivamente avere conseguenze sulla sicurezza o, più spesso, semplici bug.Quindi più possiamo fare per porre un punto interrogativo su eval, meglio è.Ogni volta che usi eval devi controllare l'integrità di ciò che stai facendo, perché è probabile che potresti farlo in un modo migliore, più sicuro e più pulito.

Per fare un esempio fin troppo tipico, per impostare il colore di un elemento con un id memorizzato nella variabile 'potato':

eval('document.' + potato + '.style.color = "red"');

Se gli autori del tipo di codice di cui sopra avessero un'idea delle basi di come funzionano gli oggetti JavaScript, si sarebbero resi conto che è possibile utilizzare parentesi quadre invece di nomi di punti letterali, ovviando alla necessità di eval:

document[potato].style.color = 'red';

...che è molto più facile da leggere e potenzialmente meno buggato.

(Ma poi, qualcuno che /veramente/ sapeva cosa stava facendo direbbe:

document.getElementById(potato).style.color = 'red';

che è più affidabile del vecchio trucco losco di accedere agli elementi DOM direttamente dall'oggetto documento.)

Credo che sia perché può eseguire qualsiasi funzione JavaScript da una stringa.Usarlo rende più semplice per le persone inserire codice non autorizzato nell'applicazione.

Mi vengono in mente due punti:

  1. Sicurezza (ma finché generi tu stesso la stringa da valutare, questo potrebbe non essere un problema)

  2. Prestazione:finché non si conosce il codice da eseguire, non è possibile ottimizzarlo.(riguardo Javascript e prestazioni, certamente Presentazione di Steve Yegge)

Passare l'input dell'utente a eval() è un rischio per la sicurezza, ma anche ogni invocazione di eval() crea una nuova istanza dell'interprete JavaScript.Questo può essere un divoratore di risorse.

Generalmente è un problema solo se stai passando l'input dell'utente eval.

Principalmente, è molto più difficile da mantenere ed eseguire il debug.È come un goto.Puoi usarlo, ma rende più difficile individuare i problemi e più difficile per le persone che potrebbero aver bisogno di apportare modifiche in seguito.

Una cosa da tenere a mente è che spesso puoi usare eval() per eseguire codice in un ambiente altrimenti limitato: i siti di social network che bloccano specifiche funzioni JavaScript a volte possono essere ingannati suddividendoli in un blocco eval -

eval('al' + 'er' + 't(\'' + 'hi there!' + '\')');

Quindi, se stai cercando di eseguire del codice JavaScript dove potrebbe non essere altrimenti consentito (Il mio spazio, ti sto guardando...) allora eval() può essere un trucco utile.

Tuttavia, per tutti i motivi sopra menzionati, non dovresti usarlo per il tuo codice, su cui hai il controllo completo: semplicemente non è necessario ed è meglio relegato nello scaffale dei "complicati hack JavaScript".

A meno che non lasci che eval() abbia un contenuto dinamico (tramite cgi o input), è sicuro e solido come tutti gli altri JavaScript nella tua pagina.

Insieme al resto delle risposte, non penso che le dichiarazioni di valutazione possano avere una minimizzazione avanzata.

Si tratta di un possibile rischio per la sicurezza, ha un ambito di esecuzione diverso ed è piuttosto inefficiente, poiché crea un ambiente di scripting completamente nuovo per l'esecuzione del codice.Vedi qui per qualche informazione in più: eval.

È abbastanza utile, tuttavia, e usato con moderazione può aggiungere molte buone funzionalità.

A meno che tu non sia sicuro al 100% che il codice da valutare provenga da una fonte attendibile (di solito la tua stessa applicazione), allora è un modo infallibile per esporre il tuo sistema a un attacco di scripting cross-site.

So che la discussione è vecchia, ma mi piace molto Questo approccio di Google e volevo condividere questa sensazione con gli altri ;)

L'altra cosa è che meglio ottieni, più cerchi di capire e finalmente non credi che qualcosa sia buono o cattivo solo perché qualcuno lo ha detto :) Questo è molto stimolante video questo mi ha aiutato a pensare di più da solo :) LE BUONE PRATICHE sono buone, ma non usarle senza pensarci :)

Non è necessariamente così male a condizione che tu sappia in quale contesto lo stai utilizzando.

Se la tua applicazione utilizza eval() per creare un oggetto da qualche JSON che è tornato da un XMLHttpRequest al tuo sito, creato dal tuo codice lato server fidato, probabilmente non è un problema.

Il codice JavaScript lato client non attendibile non può comunque fare molto.A condizione che tu stia eseguendo la cosa eval() proviene da una fonte ragionevole, stai bene.

Riduce notevolmente il livello di fiducia nella sicurezza.

Se desideri che l'utente inserisca alcune funzioni logiche e valuti AND e OR, la funzione di valutazione JavaScript è perfetta.Posso accettare due stringhe e eval(uate) string1 === string2, eccetera.

Se noti l'uso di eval() nel tuo codice, ricorda il mantra "eval() è malvagio".

Questa funzione prende una stringa arbitraria ed la esegue come codice JavaScript.Quando il codice in questione è noto in anticipo (non determinato in fase di esecuzione), non c'è motivo di utilizzare Eval ().Se il codice viene generato in modo dinamico in fase di esecuzione, c'è spesso un modo migliore per raggiungere l'obiettivo senza Eval ().Ad esempio, solo l'uso della notazione della staffa quadrata per accedere alle proprietà dinamiche è migliore e più semplice:

// antipattern
var property = "name";
alert(eval("obj." + property));

// preferred
var property = "name";
alert(obj[property]);

Utilizzando eval() Ha anche implicazioni di sicurezza, perché potresti eseguire il codice (ad esempio proveniente dalla rete) che è stato manomesso.Questo è un antipattern comune quando si ha a che fare con una risposta JSON da una richiesta Ajax.In questi casi è meglio utilizzare i metodi integrati dei browser per analizzare la risposta JSON per assicurarsi che sia sicuro e valido.Per i browser che non supportano JSON.parse() Nativo, puoi usare una libreria da json.org.

È anche importante ricordare che il passaggio delle stringhe a setInterval(), setTimeout(), e il Function() costruttore è, per la maggior parte, simile a using eval() e quindi dovrebbe essere evitato.

Dietro le quinte, JavaScript deve ancora valutare ed eseguire la stringa che passa come codice di programmazione:

// antipatterns
setTimeout("myFunc()", 1000);
setTimeout("myFunc(1, 2, 3)", 1000);

// preferred
setTimeout(myFunc, 1000);
setTimeout(function () {
myFunc(1, 2, 3);
}, 1000);

L'uso del nuovo costruttore di funzioni () è simile a Eval () e dovrebbe essere affrontato con cura.Potrebbe essere un costrutto potente ma spesso viene utilizzato in modo improprio.Se devi assolutamente usare eval(), puoi invece prendere in considerazione l'utilizzo di new Function().

Vi è un piccolo vantaggio potenziale perché il codice valutato in Nuova funzione () sarà eseguito nell'ambito di funzione locale, quindi qualsiasi variabile definita con VAR nel codice valutato non diventerà automaticamente i globali.

Un altro modo per impedire le globali automatiche è racchiudere il fileeval() chiamata in una funzione immediata.

Oltre ai possibili problemi di sicurezza se si esegue il codice inviato dall'utente, nella maggior parte dei casi esiste un modo migliore che non implica la nuova analisi del codice ogni volta che viene eseguito.Le funzioni anonime o le proprietà degli oggetti possono sostituire la maggior parte degli usi di eval e sono molto più sicure e veloci.

Questo potrebbe diventare un problema maggiore poiché la prossima generazione di browser uscirà con un certo sapore di compilatore JavaScript.Il codice eseguito tramite Eval potrebbe non funzionare altrettanto bene del resto del tuo JavaScript rispetto a questi browser più recenti.Qualcuno dovrebbe fare un po' di profilazione.

Questo è uno degli ottimi articoli che parlano di eval e di come non sia un male:http://www.nczonline.net/blog/2013/06/25/eval-isnt-evil-just-misunderstood/

Non sto dicendo che dovresti esaurire e iniziare a usare Eval () ovunque.In effetti, ci sono pochissimi buoni casi d'uso per l'esecuzione di Eval ().Ci sono sicuramente preoccupazioni per la chiarezza del codice, la debugabilità e certamente le prestazioni che non dovrebbero essere trascurate.Ma non dovresti aver paura di usarlo quando hai un caso in cui Eval () ha senso.Prova a non usarlo prima, ma non lasciare che nessuno ti spaventi nel pensare che il tuo codice sia più fragile o meno sicuro quando valuta () viene utilizzato in modo appropriato.

eval() è molto potente e può essere utilizzato per eseguire un'istruzione JS o valutare un'espressione.Ma la domanda non riguarda gli usi di eval() ma diciamo solo come la stringa che esegui con eval() viene influenzata da un soggetto malintenzionato.Alla fine eseguirai codice dannoso.Dal potere derivano grandi responsabilità.Quindi usalo saggiamente se lo stai usando.Questo non è molto correlato alla funzione eval() ma questo articolo contiene informazioni piuttosto valide: http://blogs.popart.com/2009/07/javascript-injection-attacks/Se stai cercando le basi di eval() guarda qui:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval

Non tenterò di confutare quanto detto finora, ma offrirò questo uso di eval() che (per quanto ne so) non può essere fatto in nessun altro modo.Probabilmente ci sono altri modi per codificarlo, e probabilmente modi per ottimizzarlo, ma questo viene fatto a mano e senza fronzoli per ragioni di chiarezza per illustrare un uso di eval che in realtà non ha altre alternative.Questo è:nomi di oggetti dinamici (o più precisamente) creati a livello di programmazione (in contrapposizione ai valori).

//Place this in a common/global JS lib:
var NS = function(namespace){
    var namespaceParts = String(namespace).split(".");
    var namespaceToTest = "";
    for(var i = 0; i < namespaceParts.length; i++){
        if(i === 0){
            namespaceToTest = namespaceParts[i];
        }
        else{
            namespaceToTest = namespaceToTest + "." + namespaceParts[i];
        }

        if(eval('typeof ' + namespaceToTest) === "undefined"){
            eval(namespaceToTest + ' = {}');
        }
    }
    return eval(namespace);
}


//Then, use this in your class definition libs:
NS('Root.Namespace').Class = function(settings){
  //Class constructor code here
}
//some generic method:
Root.Namespace.Class.prototype.Method = function(args){
    //Code goes here
    //this.MyOtherMethod("foo"));  // => "foo"
    return true;
}


//Then, in your applications, use this to instantiate an instance of your class:
var anInstanceOfClass = new Root.Namespace.Class(settings);

MODIFICARE:a proposito, non suggerirei (per tutti i motivi di sicurezza sottolineati finora) di basare i nomi degli oggetti sull'input dell'utente.Non riesco a immaginare alcuna buona ragione per cui vorresti farlo.Tuttavia, ho pensato di far notare che non sarebbe stata una buona idea :)

Il motore JavaScript dispone di una serie di ottimizzazioni delle prestazioni che esegue durante la fase di compilazione.Alcuni di questi si riducono alla capacità di analizzare essenzialmente staticamente il codice mentre viene letto e predeterminare dove si trovano tutte le dichiarazioni di variabili e funzioni, in modo che sia necessario meno sforzo per risolvere gli identificatori durante l'esecuzione.

Ma se il motore trova un eval(..) nel codice, deve essenzialmente presumere che tutta la sua consapevolezza della posizione dell'identificatore potrebbe non essere valida, perché non può sapere al momento della lexing esattamente quale codice puoi passare a eval(..) per modificare l'ambito lessicale, ovvero il contenuto dell'oggetto a cui si può passare per creare un nuovo ambito lessicale da consultare.

In altre parole, in senso pessimistico, la maggior parte delle ottimizzazioni che farebbe sarebbero inutili se eval(..) fosse presente, quindi semplicemente non esegue affatto le ottimizzazioni.

Questo spiega tutto.

Riferimento :

https://github.com/getify/You-Dont-Know-JS/blob/master/scope%20&%20closures/ch2.md#eval

https://github.com/getify/You-Dont-Know-JS/blob/master/scope%20&%20closures/ch2.md#performance

Non è sempre una cattiva idea.Prendiamo ad esempio la generazione del codice.Recentemente ho scritto una libreria chiamata Iperbarre che colma il divario tra dominio virtuale E manubrio.Lo fa analizzando un modello di manubrio e convertendolo in file iperscritto che viene successivamente utilizzato da virtual-dom.L'iperscritto viene generato prima come stringa e prima di restituirlo, eval() per trasformarlo in codice eseguibile.ho trovato eval() in questa particolare situazione l'esatto opposto del male.

Fondamentalmente da

<div>
    {{#each names}}
        <span>{{this}}</span>
    {{/each}}
</div>

A questa

(function (state) {
    var Runtime = Hyperbars.Runtime;
    var context = state;
    return h('div', {}, [Runtime.each(context['names'], context, function (context, parent, options) {
        return [h('span', {}, [options['@index'], context])]
    })])
}.bind({}))

Le prestazioni di eval() non è un problema in una situazione come questa perché è necessario interpretare la stringa generata solo una volta e quindi riutilizzare l'output eseguibile più volte.

Se sei curioso puoi vedere come è stata ottenuta la generazione del codice Qui.

Oserei dire che non importa se lo usi eval() in javascript che viene eseguito nei browser.*(avvertenza)

Tutti i browser moderni dispongono di una console di sviluppo in cui puoi comunque eseguire javascript arbitrario e qualsiasi sviluppatore semi-intelligente può guardare il tuo sorgente JS e inserirne tutte le parti di cui ha bisogno nella console di sviluppo per fare ciò che desidera.

*Finché gli endpoint del tuo server hanno la corretta convalida e sanificazione dei valori forniti dall'utente, non dovrebbe importare ciò che viene analizzato e valutato nel tuo javascript lato client.

Se dovessi chiedere se è adatto all'uso eval() in PHP, tuttavia, la risposta è NO, a meno che tu lista bianca tutti i valori che possono essere passati alla tua istruzione eval.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top