Cosa costituisce un "uso improprio" della funzione javascript Eval? [chiuso]


13

Eval è una caratteristica del linguaggio notoriamente controversa. Douglas Crockford lo respinge. Mi chiedo quali siano i rischi specifici che Eval comporta. Secondo questa domanda, Improper use of eval opens up your code for injection attacks.

Quali sono alcuni usi impropri del comando Eval e quali falle di sicurezza aprono?

Risposte:


31

All'epoca in cui stavo implementando il motore JScript, ho raccomandato di stampare le magliette EVAL IS EVIL , ma purtroppo non ci siamo mai riusciti.

Il mio più grande problema con eval non è l'evidente attacco di iniezione di codice dannoso, anche se questo è certamente di enorme preoccupazione. Il mio problema più grande è che le persone tendono a usarlo come un martello veramente grande per risolvere problemi davvero piccoli. La maggior parte degli usi del mondo reale che ho visto di "eval" in natura quando facevo parte del team di JScript avrebbero potuto essere banalmente risolti utilizzando una tabella di ricerca; e poiché ogni oggetto in JScript è già una tabella di ricerca , non è che fosse un onere gravoso. Eval avvia nuovamente il compilatore e distrugge completamente la capacità del compilatore di ottimizzare il codice .

Per ulteriori riflessioni in questo senso vedi i miei articoli del 2003 sull'argomento:

Malvagità generale:

http://blogs.msdn.com/b/ericlippert/archive/2003/11/01/53329.aspx

Malvagità di attacco all'iniezione:

http://blogs.msdn.com/b/ericlippert/archive/2003/11/04/53335.aspx


Cosa ne evalpensi di grandi blocchi di codice come piace ad applicazioni come JSPacker? JSPacker + gzip di solito produce file di dimensioni inferiori rispetto a ciascuna soluzione da sola, ma come giustamente fai notare, sta essenzialmente accendendo un compilatore due volte sullo stesso pezzo di codice, oltre ad un sovraccarico per sostituire le stringhe.
Matthew Scharley,

2
@Matthew: c'è spesso un compromesso tra spazio e tempo, e approfittare di quel compromesso a volte può essere una grande vittoria. Se lo scopo della tecnica è migliorare le prestazioni, la mia opinione è che se un'attenta misurazione mostra che si tratta di una vittoria significativa in scenari realistici senza introdurre falle di sicurezza, ottimo, fatelo. Ma non so abbastanza della tecnica specifica per criticare i suoi dettagli.
Eric Lippert,

Vorrei che una delle risposte che avevo visto sia qui o su SO stesso avrei detto che cosa il vostro secondo link afferma: che eval()è non è un rischio per la sicurezza sul client il codice (browser).
sq33G

4

La maggior parte dei buchi di sicurezza ha lo stesso tipo di buchi dell'iniezione SQL, vale a dire concatenare l'input dell'utente nel codice JavaScript. La differenza è che mentre ci sono modi per garantire che ciò non accada con SQL, non c'è molto che puoi fare con JavaScript.

Come esempio banale e inutile, un semplice calcolatore JavaScript:

textbox1.value = eval(textbox2.value);

Un esempio di utilizzo corretto sono alcuni dei packer JavaScript che comprimono JavaScript estraendo parole comuni e sostituendole con brevi sostituzioni di 1-2 caratteri. Il packer emette quindi tutto questo insieme al codice di sostituzione della stringa basato sul dizionario generato, quindi elimina il risultato.


1

Ci sono alcune cose che sono impossibili da fare in JS senza una funzione eval-simile ( eval, Function, e forse più).

Prendi applyad esempio. È facile da usare quando lo si utilizza su normali chiamate di funzione:

foo.apply(null, [a, b, c])

Ma come faresti per gli oggetti che stai creando tramite una nuova sintassi?

new Foo.apply(null, [a, b, c]) non funziona, né forme simili.

Ma puoi aggirare questa limitazione tramite evalo Function(io uso Functionin questo esempio):

Function.prototype.New = (function () {
    var fs = [];
    return function () {
        var f = fs[arguments.length];
        if (f) {
            return f.apply(this, arguments);
        }
        var argStrs = [];
        for (var i = 0; i < arguments.length; ++i) {
            argStrs.push("a[" + i + "]");
        }
        f = new Function("var a=arguments;return new this(" + argStrs.join() + ");");
        if (arguments.length < 100) {
            fs[arguments.length] = f;
        }
        return f.apply(this, arguments);
    };
}) ();

Esempio:

Foo.New.apply(null, [a, b, c]);

Certo, potresti costruire manualmente le funzioni che Function.prototype.Newusa, ma non solo questo è dettagliato e goffo, (per definizione) deve essere finito. Functionconsente al codice di funzionare per qualsiasi numero di argomenti.


2
È vero, ma la domanda del PO era " Quali sono alcuni usi impropri del comando Eval e quali buchi di sicurezza aprono? ", Non " Qual è un buon uso eval()? "
Ross Patterson

1
@RossPatterson: Immagino di aver guardato per lo più il titolo della domanda ahah.
Thomas Eding,

Tuttavia, +1 per trovare un buon uso per una funzione di linguaggio volgare :-)
Ross Patterson,

1

Una risposta in qualche modo diretta da parte mia è stata lo sviluppo di un'area di test API orientata agli sviluppatori. Abbiamo fornito un'area di testo su una pagina e un pulsante Esegui. Il punto centrale della pagina era che potevano provare cose in Javascript contro la nostra API di comunicazione iframe che non era così facile da fare in un ambiente locale.

Qualunque cosa dannosa che avrebbe potuto essere fatto in quel caso avrebbe potuto essere fatta anche dallo sviluppatore aprendo i loro strumenti F12.


0

Sono d'accordo sul fatto che dovrebbe essere usato molto raramente, ma ho trovato un caso utile per eval.

C'è una nuova funzionalità sperimentale in Firefox chiamata asm.js con cui ho lavorato. Consente di compilare un sottoinsieme limitato del linguaggio Javascript in codice nativo. Sì, è fantastico, ma ha dei limiti. Puoi pensare al sottoinsieme limitato di Javascript come un linguaggio simile a C incorporato in Javascript. Non è davvero pensato per essere letto o scritto dagli umani.

Questo sottoinsieme limitato di Javascript non mi permette di iniettare il mio codice generato dal runtime nel codice compilato una volta che è stato compilato.

Ho scritto del codice che consente a un utente di scrivere, in notazione familiare, un'espressione matematica e di convertirlo al volo in codice asm.js. A meno che non volessi che il codice venisse elaborato sul lato server (cosa che non faccio), evalè l'unico strumento che mi permette di far elaborare il codice risultante dal browser in tempo reale.


0

Come sottolineato da altri, la cosa più importante quando si lavora evalè proteggerla. Per questo, vuoi fare un controllo approfondito degli argomenti, e mantenere evalil codice semplice poiché in genere è molto più difficile mantenere e proteggere il codice generato in fase di esecuzione.

Detto questo, mi piace usare evalper due tipi di cose (anche se probabilmente ci potrebbero essere alternative migliori, meno malvagie):

  1. Poiché evalè un modo di "codice di memorizzazione nella cache esplicita", può essere utilizzato per migliorare le prestazioni. Tieni presente che gli ottimizzatori vengono sempre migliorati, ma non esiste alcuna garanzia su cosa possano fare per te. Rendendo le cose esplicite nel codice, puoi effettivamente aiutare l'ottimizzatore a prendere decisioni più intelligenti.
  2. Può anche essere utilizzato per fornire forme base di sicurezza dei tipi, nonché altre funzionalità linguistiche che mancano a JS, senza peggiorare le prestazioni.

Questo approccio di iteratore di oggetti precompilato , ad esempio, mostra chiari vantaggi in termini di prestazioni quando si utilizza evalper l'iterazione delle proprietà degli oggetti. Mostra anche gli inizi di un potente sistema di tipi in grado di fornire un controllo implicito dei vincoli e molto altro, a costo minimo o nullo.

Molti sviluppatori JavaScript esperti probabilmente sottolineano che questa è una tana di coniglio, poiché, se inizi a scrivere Javascript in questo modo, essenzialmente cambi il modo in cui usi la lingua. Ciò, tuttavia, potrebbe non essere necessariamente una cosa negativa per coloro che amano Javascript, ma mancano anche le funzionalità del linguaggio fondamentale che possono essere raggiunte solo cambiando il modo in cui utilizziamo il linguaggio stesso.


-3

Ho una situazione in cui eval sembra la strada da percorrere, valutando una stringa e restituendo una variabile esistente il cui nome è lo stesso della stringa.

Ho diverse tabelle: table1ResultsTable, table2ResultsTable, tableNResultsTable. Ho variabili impostate con gli stessi nomi, che sono oggetti databili jQuery. Li uso per impostare le tabelle e chiamare funzioni datatable jQuery su di esse.

A ogni tabella è assegnata class = "resultsTable". Ora, devo ottenere la variabile quando si fa clic sulla tabella. Sto facendo questo:

$('resultsTable).on('click', 'td', function(event) {
    var cResultsTable = eval(event.target.parentElement.parentElement.parentElement.id);
    [etc]
});

Quindi sto ottenendo l'id della tabella in cui è stata cliccata la cella, che ha lo stesso nome della variabile oggetto datatable corrispondente ad essa. Se qualcuno ha un suggerimento per un miglioramento, mi piacerebbe saperlo.


1
Perché hai bisogno di eval? L'id dovrebbe essere una stringa semplice, non un codice. Comunque, event.target.parentElement.parentElement.parentElementè orribile. Inoltre, mi aspetto che la chiamata eval generi un errore "errore di riferimento: [id] non definito", a meno che tu non stia usando deliberatamente ID valutabili (che sono rotti, sbagliati e potrebbero causare cose strane se finisci generare ID duplicati).
Brian,

Forse non mi sto chiarendo. L'ID è una stringa semplice. È stato selezionato l'id della tabella. Ho anche una variabile oggetto (impostata con il metodo jQuery datatable (), facendo riferimento alla stessa tabella) con lo stesso nome dell'ID. Sto cercando di ottenere quella variabile, per accedere alle sue funzioni (in effetti, per aggiungere la classe "row_selected" alla riga selezionata), quando si fa clic sulla tabella. Da quando ho scritto questo, ho trovato un miglioramento, tuttavia. Ho appena inserito tutti i riferimenti agli oggetti in un array, ho nominato gli elementi uguali all'id e ho inserito la stringa id in quello per ottenere l'oggetto ref.
BobRodes

Brian, se hai un modo migliore per trovare l'ID del tavolo su cui è stato cliccato, sono tutto a posto. Per la funzione di database, devo gestire l'evento click contro la cella e aggiungere la classe row_selected al suo parentNode. Perché non posso semplicemente gestire l'evento di riga e aggiungere la classe direttamente ad esso, non lo so, ma la riga non viene visualizzata come selezionata quando lo faccio.
BobRodes

1
Forse non mi sto chiarendo. Se chiami eval su una stringa semplice (cioè non-JS), lancerai un'eccezione. Quindi, il tuo uso di eval non ha senso. Se ti capita di generare una variabile oggetto con lo stesso nome dell'ID, il tuo codice funzionerà ... ma mi sembra rotto. Preferirei creare la variabile usando document.getElementById(ID).MySpecialProperty = MYSPECIALPROPERTYVALUE(per non dire che è eccezionale, ma è meglio di eval). Come sottolinea Eric Lippert, "ogni oggetto in JScript è già una tabella di ricerca".
Brian

Ok, quindi stai dicendo di aggiungere una proprietà al riferimento dell'elemento e impostarla sul riferimento dell'oggetto datatable? Anche per me sembra più stretto.
BobRodes
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.