Quando JavaScript () di eval non è male?


263

Sto scrivendo del codice JavaScript per analizzare le funzioni inserite dall'utente (per funzionalità simili a fogli di calcolo). Dopo aver analizzato la formula, ho potuto convertirlo in JavaScript ed eseguirlo eval()per ottenere il risultato.

Tuttavia, ho sempre evitato di usarlo eval()se posso evitarlo perché è malvagio (e, giustamente o erroneamente, ho sempre pensato che fosse ancora più malvagio in JavaScript, perché il codice da valutare potrebbe essere modificato dall'utente ).

Quindi, quando va bene usarlo?


5
La maggior parte delle librerie JSON non utilizza infatti eval under the hood, esattamente per proteggersi dai rischi per la sicurezza.
Sean McMillan,

11
@Sean - Sia JQuery che Prototype usano eval (JQuery lo utilizza tramite una nuova funzione)
plodder

5
@plodder - Dove stai ottenendo le tue informazioni? jQuery ha utilizzato il nativo JSON.parse () dall'1.4 (già nel 1/2010)! Guarda tu stesso: code.jquery.com/jquery-1.4.js
ken

3
"Ovviamente si deve usare eval () per analizzare JSON" - questo non è vero, al contrario - non si dovrebbe usare eval per analizzare JSON! Usa lo script json2.js di Douglas Crockfords (creatore di JSON) da json.org !
TMS

11
@Tomas l'ironia del fatto che json2.js usa eval per analizzare JSON
tobyodavies

Risposte:


262

Vorrei prendere un momento per affrontare la premessa della tua domanda: che eval () è " malvagio ". La parola " male ", usata dalle persone del linguaggio di programmazione, di solito significa "pericolosa", o più precisamente "capace di causare molti danni con un comando dall'aspetto semplice". Quindi, quando va bene usare qualcosa di pericoloso? Quando sai qual è il pericolo e quando stai prendendo le precauzioni appropriate.

Al punto, diamo un'occhiata ai pericoli nell'uso di eval (). Probabilmente ci sono molti piccoli pericoli nascosti proprio come qualsiasi altra cosa, ma i due grandi rischi - il motivo per cui eval () è considerato malvagio - sono le prestazioni e l'iniezione di codice.

  • Performance - eval () esegue l'interprete / compilatore. Se il tuo codice è compilato, allora questo è un grande successo, perché devi chiamare un compilatore possibilmente pesante nel mezzo del runtime. Tuttavia, JavaScript è ancora principalmente un linguaggio interpretato, il che significa che chiamare eval () non è un grande successo di prestazioni nel caso generale (ma vedi le mie osservazioni specifiche di seguito).
  • Code injection - eval () potenzialmente esegue una stringa di codice con privilegi elevati. Ad esempio, un programma in esecuzione come amministratore / root non vorrebbe mai eval () l'input dell'utente, perché quell'input potrebbe potenzialmente essere "rm -rf / etc / important-file" o peggio. Ancora una volta, JavaScript in un browser non ha questo problema, perché il programma è comunque in esecuzione nell'account dell'utente. JavaScript sul lato server potrebbe avere questo problema.

Passa al tuo caso specifico. Da quello che ho capito, stai generando tu stesso le stringhe, quindi supponendo che tu stia attento a non consentire la generazione di una stringa come "rm -rf qualcosa di importante", non c'è rischio di iniezione di codice (ma ricorda, è molto, molto difficile assicurarlo nel caso generale). Inoltre, se stai eseguendo il browser, l'iniezione di codice è un rischio piuttosto lieve, credo.

Per quanto riguarda le prestazioni, dovrai ponderarlo contro la facilità di codifica. È mia opinione che se stai analizzando la formula, potresti anche calcolare il risultato durante l'analisi piuttosto che eseguire un altro parser (quello all'interno di eval ()). Ma potrebbe essere più facile codificare usando eval () e il colpo di performance sarà probabilmente impercettibile. Sembra che eval () in questo caso non sia più malvagio di qualsiasi altra funzione che potrebbe farti risparmiare un po 'di tempo.


78
Non stai affrontando il problema del codice che usa eval essendo difficile da eseguire il debug
bobobobo,

48
L'iniezione di codice è un problema molto serio per javascript se sei assolutamente preoccupato per i dati del tuo utente. Il codice iniettato verrà eseguito (nel browser) come se provenisse dal tuo sito, consentendogli di eseguire qualsiasi tipo di shenanigan che l'utente potrebbe eseguire manualmente. Se permetti al codice (di terze parti) di accedere alla tua pagina, può ordinare cose per conto del tuo cliente, o cambiare il suo gravatar o qualunque cosa possano fare attraverso il tuo sito. Essere molto attenti. Consentire agli hacker di possedere i tuoi clienti è altrettanto male che far loro possedere il tuo server.
Sean McMillan,

71
Se i dati provengono dal tuo server e sono qualcosa che tu, lo sviluppatore ha generato, non vi è alcun danno nell'uso di eval (). Il vero danno è credere a tutto ciò che leggi. Vedi molte persone dire che eval () è malvagio e non hanno idea del perché tranne che lo leggono da qualche parte.
Vince Panuccio

42
@Sean McMillan: voglio crederti, ma se qualcuno intercetterà e cambierà javascript eval()dal tuo server, potrebbe anche cambiare la fonte della pagina in primo luogo, e anche prendere il controllo delle informazioni dell'utente. . . Non vedo la differenza.
Walt W

20
Ri "Iniezione di codice - ... Ancora una volta, JavaScript in un browser non ha questo problema" & "Inoltre, se stai eseguendo nel browser, l'iniezione di codice è un rischio piuttosto lieve, credo." Stai suggerendo che l'iniezione di codice nel browser non è un problema? XSS è stato nella top 3 delle classifiche nella top 10 di OWASP per diversi anni consecutivi.
Mike Samuel,

72

eval()non è male. Oppure, se lo è, è male allo stesso modo in cui riflessione, I / O di file / rete, threading e IPC sono "cattivi" in altre lingue.

Se, per il tuo scopo , eval()è più veloce dell'interpretazione manuale, o rende il tuo codice più semplice o più chiaro ... allora dovresti usarlo. Se nessuno dei due, allora non dovresti. Semplice come quella.


5
Uno di questi scopi potrebbe essere quello di generare codice ottimizzato che sarebbe troppo lungo o troppo ripetitivo per scrivere a mano. Il tipo di cose che, in LISP, richiederebbe una macro.
wberry,

5
Questo è un consiglio così generale che potrebbe essere applicato letteralmente a qualsiasi blocco di codice esistente. In realtà non aggiunge nulla a questa domanda; in particolare, non aiuta nessuno che viene qui a determinare se il suo particolare utilizzo è problematico o meno.
jpmc26,

2
Più veloce, più semplice, più chiaro ... Questa risposta non copre abbastanza bene le implicazioni di sicurezza.
Ruud Helderman,

55

Quando ti fidi della fonte.

Nel caso di JSON, è più o meno difficile manomettere l'origine, poiché proviene da un server Web che controlli. Fintanto che lo stesso JSON non contiene dati caricati da un utente, non ci sono grossi svantaggi nell'utilizzo di eval.

In tutti gli altri casi farei di tutto per assicurarsi che i dati forniti dagli utenti siano conformi alle mie regole prima di inviarli a eval ().


13
Una stringa json dovrebbe sempre essere testata rispetto alla grammatica json prima di usarla in eval (). Quindi la stringa json "{foo: alert ('XSS')}" non passerebbe poiché "alert ('XSS')" non è un valore corretto.
Gumbo,

3
Bene, allora usa HTTPS. OTOH: man-in-the-middle non è lo scenario di attacco tipico per l'app web varietà da giardino, mentre lo è lo scripting cross-site.
Tomalak,

7
evalinoltre non analizzerà correttamente tutte le stringhe JSON valide. Ad esempio, JSON.parse(' "\u2028" ') === "\u2028"ma eval(' "\u2028" ')solleva un'eccezione perché U + 2028 è una nuova riga in JavaScript ma non è una nuova riga per quanto riguarda JSON.
Mike Samuel,

1
@Justin - se il protocollo è compromesso, beh, in genere il caricamento della pagina iniziale sarebbe stato inviato su quello stesso protocollo, e quindi è un punto controverso perché il client è già compromesso come può essere.
antinome,

1
Splendidamente detto @Tomalak, l'ho menzionato nella mia risposta proprio ora! Eccezionale!
NiCk Newman,

25

Vediamo gente vera:

  1. Ogni browser principale ora ha una console integrata che il tuo potenziale hacker può usare con abbondanza per invocare qualsiasi funzione con qualsiasi valore - perché dovrebbero preoccuparsi di usare un'istruzione eval - anche se potessero?

  2. Se ci vogliono 0,2 secondi per compilare 2000 righe di JavaScript, qual è il mio degrado delle prestazioni se valuto quattro righe di JSON?

Anche la spiegazione di Crockford per "eval is evil" è debole.

eval è il male, la funzione eval è la caratteristica più abusata di JavaScript. Evitalo

Come potrebbe dire lo stesso Crockford "Questo tipo di affermazione tende a generare nevrosi irrazionali. Non comprarlo."

Comprendere eval e sapere quando potrebbe essere utile è molto più importante. Ad esempio, eval è uno strumento sensato per valutare le risposte del server generate dal software.

A proposito: Prototype.js chiama eval direttamente cinque volte (incluso in evalJSON () e evalResponse ()). jQuery lo usa in parseJSON (tramite il costruttore di funzioni).


10
JQuery utilizza la funzione integrata JSON.parse del browser, se disponibile (che è molto più veloce e sicura), usando eval solo come meccanismo di fallback. L'affermazione "eval is evil" è una linea guida ragionevolmente buona.
jjmontes,

30
Ri "Ogni browser principale ora ha una console integrata ...". L'iniezione di codice è un problema quando un utente può inserire il codice che viene quindi eseguito nel browser di un altro utente. Le console del browser non consentono da sole a un utente di eseguire il codice nel browser di un altro utente, quindi sono irrilevanti quando decidono se valga la pena proteggere dall'iniezione di codice.
Mike Samuel,

28
"Ogni browser principale ora ha una console integrata ... perché dovrebbero preoccuparsi di usare un'istruzione eval?" - Sei lontano dal segno. Ti suggerisco di modificare la risposta. La capacità di un utente di iniettare codice che può essere eseguito nel browser di un altro è un grosso problema. Ed è qui che devi diventare davvero reale.
akkishore il

5
@akkishore, apprezzerò se ti viene in mente un esempio di vita reale che supporta le tue affermazioni sopra dichiarate.
Akash Kava,

7
@AkashKava Quello che non riesci a capire, è che se invio javascript nella mia casella di commento e quel javascript arriva al database. Quando un altro utente visualizza quel commento (in cui ho inserito javascript), eval prenderà quel javascript al momento del rendering e lo valuterà usando l'interprete, facendo eseguire il mio javascript incorporato sul browser dell'altro utente. In questo modo, posso ottenere tutti i tipi di informazioni. Il loro nome utente, il loro ID utente nel database, il loro indirizzo e-mail, ecc. Questa non è una risposta difficile, se avessi Googled XSS, vedresti in circa 10 secondi perché è un problema.
Kyle Richter,

18

Tendo a seguire il consiglio di Crockford per eval()evitarlo del tutto. Anche i modi che sembrano richiederlo non lo fanno. Ad esempio, setTimeout()consente di passare una funzione piuttosto che valutare.

setTimeout(function() {
  alert('hi');
}, 1000);

Anche se è una fonte attendibile , non lo uso, perché il codice restituito da JSON potrebbe essere confuso, il che nella migliore delle ipotesi potrebbe fare qualcosa di traballante, nel peggiore dei casi, esporre qualcosa di brutto.


2
Penso che i bug nel formattatore JSON sul lato server siano sicuramente un problema. La risposta dal server dipende da qualsiasi tipo di testo inviato dall'utente? Quindi devi guardare per XSS.
Swilliams,

3
Se il tuo server web non è autenticato tramite HTTPS, potresti subire una sorta di attacco man-in-the-middle in cui un altro host intercetta la richiesta e invia i suoi dati.
Ben Combee,

11
Se qualcuno può eseguire un attacco man-in-the-middle, può facilmente iniettare qualsiasi cosa nei tuoi script.
el.pescado,

10
Non dovresti fare affidamento sul tuo codice javascript ... Non fare affidamento su nulla che gira sul lato client ... Se qualcuno attacca man-in-the-middle perché dovrebbe fare casino con i tuoi oggetti json? Può servirti una pagina web diversa e file js diversi ...
Calmarius,

5
Personalmente non mi piace l'argomento "ci sono sempre altri modi per farlo". Ad esempio, si potrebbe anche dire che ci sono sempre modi per evitare la programmazione orientata agli oggetti. Ciò non significa che non sia un'ottima opzione. Se capisci eval ed i suoi pericoli, può essere un ottimo strumento da usare nelle giuste situazioni.
dall

4

Ho visto persone che sostenevano di non usare eval, perché è malvagio , ma ho visto le stesse persone usare Function e setTimeout in modo dinamico, quindi usano eval sotto i cofani : D

A proposito, se il tuo sandbox non è abbastanza sicuro (ad esempio, se stai lavorando su un sito che consente l'iniezione di codice) eval è l'ultimo dei tuoi problemi. La regola di base della sicurezza è che tutti gli input sono malvagi, ma in caso di JavaScript anche JavaScript stesso potrebbe essere malvagio, perché in JavaScript puoi sovrascrivere qualsiasi funzione e non puoi essere sicuro di utilizzare quello reale, quindi, se un codice dannoso inizia prima di te, non puoi fidarti di nessuna funzione integrata di JavaScript: D

Ora l'epilogo di questo post è:

Se ne hai davvero bisogno (l'80% del tempo NON è necessario) e sei sicuro di quello che stai facendo, usa solo eval (o migliore funzione;)), chiusure e OOP coprono l'80 / 90% del caso in cui eval può essere sostituito usando un altro tipo di logica, il resto è un codice generato dinamicamente (ad esempio, se stai scrivendo un interprete) e come hai già detto valutando JSON (qui puoi usare la valutazione sicura di Crockford;))


E come sottolineato dallo stesso Crockford , gli attuali browser Web hanno una funzione integrata JSON.parse .
Ruud Helderman,

4

Eval è complementare alla compilazione che viene utilizzata nel modello del codice. Per modello intendo che scrivi un generatore di template semplificato che genera un utile codice template che aumenta la velocità di sviluppo.

Ho scritto un framework in cui gli sviluppatori non usano EVAL, ma usano il nostro framework e a sua volta quel framework deve usare EVAL per generare template.

Le prestazioni di EVAL possono essere aumentate utilizzando il seguente metodo; invece di eseguire lo script, è necessario restituire una funzione.

var a = eval("3 + 5");

Dovrebbe essere organizzato come

var f = eval("(function(a,b) { return a + b; })");

var a = f(3,5);

La memorizzazione nella cache f migliorerà sicuramente la velocità.

Inoltre Chrome consente il debug di tali funzioni molto facilmente.

Per quanto riguarda la sicurezza, l'utilizzo di eval o no non farà praticamente alcuna differenza,

  1. Innanzitutto, il browser richiama l'intero script in una sandbox.
  2. Qualsiasi codice che è male in EVAL, è cattivo nel browser stesso. L'aggressore o chiunque può facilmente iniettare un nodo di script in DOM e fare qualsiasi cosa se può valutare qualsiasi cosa. Non usare EVAL non farà alcuna differenza.
  3. È soprattutto una scarsa sicurezza sul lato server che è dannosa. Una scarsa convalida dei cookie o una scarsa implementazione dell'ACL sul server causano la maggior parte degli attacchi.
  4. Una recente vulnerabilità di Java, ecc. Era presente nel codice nativo di Java. JavaScript era ed è progettato per funzionare in un sandbox, mentre le applet sono state progettate per funzionare all'esterno di un sandbox con certificati, ecc. Che portano a vulnerabilità e molte altre cose.
  5. Scrivere codice per imitare un browser non è difficile. Tutto quello che devi fare è inviare una richiesta HTTP al server con la tua stringa agente utente preferita. Tutti gli strumenti di test simulano comunque i browser; se un attaccante vuole farti del male, EVAL è la sua ultima risorsa. Esistono molti altri modi per gestire la sicurezza lato server.
  6. Il DOM del browser non ha accesso ai file e non un nome utente. In realtà nulla sulla macchina a cui Eval può dare accesso.

Se la tua sicurezza lato server è abbastanza solida da consentire a chiunque di attaccare da qualsiasi luogo, non dovresti preoccuparti di EVAL. Come ho già detto, se EVAL non esistesse, gli aggressori hanno molti strumenti per hackerare il tuo server indipendentemente dalla capacità EVAL del tuo browser.

Eval è utile solo per generare alcuni modelli per eseguire elaborazioni di stringhe complesse basate su qualcosa che non viene utilizzato in anticipo. Ad esempio, preferirò

"FirstName + ' ' + LastName"

Al contrario di

"LastName + ' ' + FirstName"

Come il mio nome visualizzato, che può provenire da un database e che non è codificato.


Puoi usare la funzione invece di eval - function (first, last) { return last + ' ' + first }.
Konrad Borowski,

I nomi delle colonne provengono dal database.
Akash Kava,

3
La minaccia di evalè per lo più altri utenti . Supponiamo che tu abbia una pagina delle impostazioni e che ti consenta di impostare il modo in cui il tuo nome appare agli altri. Diciamo anche che non stavi pensando molto chiaramente quando l'hai scritto, quindi la tua casella di selezione ha opzioni come <option value="LastName + ' ' + FirstName">Last First</option>. Apro i miei strumenti di sviluppo, cambio l' valueopzione di in alert('PWNED!'), seleziono l'opzione modificata e invio il modulo. Ora, ogni volta che un'altra persona può vedere il mio nome visualizzato, quel codice viene eseguito.
cHao,

@cHao, Quello di cui stai parlando è un esempio di scarsa sicurezza lato server, il server non dovrebbe mai accettare dati che possono essere eseguiti come codice nel browser di nessuno. Ancora una volta, non si è capito il concetto di scarsa sicurezza lato server.
Akash Kava,

1
Puoi lamentarti della sicurezza sul lato server se vuoi, ma l'intero punto evalè eseguire il codice che non fa parte dello script che hai scritto. Se non hai bisogno del potere di farlo (e non lo fai quasi mai), evitare evalaiuta a risolvere un'intera categoria di problemi. Questa è una buona cosa se il tuo codice lato server è meno che perfetto.
cHao,

4

Durante il debug in Chrome (v28.0.1500.72), ho scoperto che le variabili non sono legate alle chiusure se non vengono utilizzate in una funzione nidificata che produce la chiusura. Immagino sia un'ottimizzazione del motore JavaScript.

MA : quando eval()viene utilizzato all'interno di una funzione che provoca una chiusura, TUTTE le variabili delle funzioni esterne sono legate alla chiusura, anche se non vengono utilizzate affatto. Se qualcuno ha il tempo di testare se possono essere prodotte perdite di memoria, per favore lasciami un commento qui sotto.

Ecco il mio codice di prova:

(function () {
    var eval = function (arg) {
    };

    function evalTest() {
        var used = "used";
        var unused = "not used";

        (function () {
            used.toString();   // Variable "unused" is visible in debugger
            eval("1");
        })();
    }

    evalTest();
})();

(function () {
    var eval = function (arg) {
    };

    function evalTest() {
        var used = "used";
        var unused = "not used";

        (function () {
            used.toString();   // Variable "unused" is NOT visible in debugger
            var noval = eval;
            noval("1");
        })();
    }

    evalTest();
})();

(function () {
    var noval = function (arg) {
    };

    function evalTest() {
        var used = "used";
        var unused = "not used";

        (function () {
            used.toString();    // Variable "unused" is NOT visible in debugger
            noval("1");
        })();
    }

    evalTest();
})();

Quello che mi piace sottolineare qui è che eval () non deve necessariamente riferirsi alla eval()funzione nativa . Tutto dipende dal nome della funzione . Quindi, quando si chiama il nativo eval()con un nome alias (diciamo var noval = eval;e poi in una funzione interna noval(expression);), la valutazione di expressionpotrebbe fallire quando si riferisce a variabili che dovrebbero far parte della chiusura, ma in realtà non lo è.



3

Linea di fondo

Se hai creato o disinfettato il codice eval, non è mai male .

Leggermente più dettagliato

evalè dannoso se in esecuzione sul server utilizzando l'input inviato da un client che non è stato creato dallo sviluppatore o che non è stato disinfettato dallo sviluppatore .

evalnon è male se in esecuzione sul client, anche se si utilizza l'input non autenticato creato dal client .

Ovviamente dovresti sempre disinfettare l'input, in modo da avere un certo controllo su ciò che consuma il tuo codice.

Ragionamento

Il client può eseguire qualsiasi codice arbitrario che desidera, anche se lo sviluppatore non lo ha codificato; Questo è vero non solo per ciò che viene valutato, ma per la chiamata a evalse stesso .


2

L'unica istanza in cui dovresti usare eval () è quando devi eseguire JS dinamico al volo. Sto parlando di JS che scarichi in modo asincrono dal server ...

... E 9 volte su 10 potresti facilmente evitare di farlo rifattorizzando.


Al giorno d'oggi, ci sono altri (e migliori) modi per caricare JavaScript in modo asincrono dal server: w3bits.com/async-javascript
Ruud Helderman

1

evalraramente è la scelta giusta. Mentre ci possono essere numerosi casi in cui puoi realizzare ciò che devi realizzare concatenando uno script insieme ed eseguendolo al volo, in genere hai a tua disposizione tecniche molto più potenti e gestibili: notazione associativa-array ( obj["prop"]è la stessa di obj.prop) , chiusure, tecniche orientate agli oggetti, tecniche funzionali - usali invece.


1

Per quanto riguarda lo script client, penso che il problema della sicurezza sia un punto controverso. Tutto ciò che viene caricato nel browser è soggetto a manipolazione e deve essere trattato come tale. Non vi è alcun rischio nell'uso di un'istruzione eval () quando esistono modi molto più semplici per eseguire codice JavaScript e / o manipolare oggetti nel DOM, come la barra degli URL nel browser.

javascript:alert("hello");

Se qualcuno vuole manipolare il proprio DOM, dico di andarsene. La sicurezza per prevenire qualsiasi tipo di attacco dovrebbe sempre essere la responsabilità dell'applicazione server, punto.

Da un punto di vista pragmatico, non c'è alcun vantaggio nell'usare un eval () in una situazione in cui le cose possono essere fatte diversamente. Tuttavia, ci sono casi specifici in cui DOVREBBE essere usato un eval. In tal caso, può sicuramente essere fatto senza alcun rischio di far saltare in aria la pagina.

<html>
    <body>
        <textarea id="output"></textarea><br/>
        <input type="text" id="input" />
        <button id="button" onclick="execute()">eval</button>

        <script type="text/javascript">
            var execute = function(){
                var inputEl = document.getElementById('input');
                var toEval = inputEl.value;
                var outputEl = document.getElementById('output');
                var output = "";

                try {
                    output = eval(toEval);
                }
                catch(err){
                    for(var key in err){
                        output += key + ": " + err[key] + "\r\n";
                    }
                }
                outputEl.value = output;
            }
        </script>
    <body>
</html>

6
Ri "Non c'è rischio nell'uso di un'istruzione eval () quando ci sono modi molto più semplici per eseguire javascript e / o manipolare oggetti nel DOM". L'iniezione di codice è un problema quando un utente può inserire il codice che viene quindi eseguito nel browser di un altro utente. Le console del browser non consentono da sole a un utente di eseguire il codice nel browser di un altro utente, quindi sono irrilevanti quando decidono se valga la pena proteggere dall'iniezione di codice.
Mike Samuel,

Non è <head></head>richiesto, anche se vuoto?
Peter Mortensen,

2
Questa risposta ignora completamente i rischi di XSS .
Ruud Helderman,

1

Sul lato server, eval è utile quando si tratta di script esterni come sql o influxdb o mongo. Dove è possibile effettuare la convalida personalizzata in fase di runtime senza distribuire nuovamente i servizi.

Ad esempio un servizio di realizzazione con i seguenti metadati

{
  "568ff113-abcd-f123-84c5-871fe2007cf0": {
    "msg_enum": "quest/registration",
    "timely": "all_times",
    "scope": [
      "quest/daily-active"
    ],
    "query": "`SELECT COUNT(point) AS valid from \"${userId}/dump/quest/daily-active\" LIMIT 1`",
    "validator": "valid > 0",
    "reward_external": "ewallet",
    "reward_external_payload": "`{\"token\": \"${token}\", \"userId\": \"${userId}\", \"amountIn\": 1, \"conversionType\": \"quest/registration:silver\", \"exchangeProvider\":\"provider/achievement\",\"exchangeType\":\"payment/quest/registration\"}`"
  },
  "efdfb506-1234-abcd-9d4a-7d624c564332": {
    "msg_enum": "quest/daily-active",
    "timely": "daily",
    "scope": [
      "quest/daily-active"
    ],
    "query": "`SELECT COUNT(point) AS valid from \"${userId}/dump/quest/daily-active\" WHERE time >= '${today}' ${ENV.DAILY_OFFSET} LIMIT 1`",
    "validator": "valid > 0",
    "reward_external": "ewallet",
    "reward_external_payload": "`{\"token\": \"${token}\", \"userId\": \"${userId}\", \"amountIn\": 1, \"conversionType\": \"quest/daily-active:silver\", \"exchangeProvider\":\"provider/achievement\",\"exchangeType\":\"payment/quest/daily-active\"}`"
  }
}

Che poi permettono,

  • Iniezione diretta di oggetti / valori attraverso una stringa letterale in un json, utile per creare modelli di testi

  • Può essere usato come comparatore, diciamo che stabiliamo regole su come validare quest o eventi in CMS

Contro di questo:

  • Possono essere errori nel codice e rompere le cose nel servizio, se non completamente testati.

  • Se un hacker può scrivere script sul tuo sistema, allora sei praticamente fregato.

  • Un modo per convalidare lo script è mantenere l'hash degli script in un luogo sicuro, in modo da poterli controllare prima di eseguirlo.


Bello. Quando ho posto la domanda non avevo nemmeno pensato al server lato server.
Richard Turner,

1

Penso che qualsiasi caso di giustificazione di valutazione sarebbe raro. È più probabile che tu lo usi pensando che sia giustificato di quanto tu debba usarlo quando è effettivamente giustificato.

I problemi di sicurezza sono i più noti. Ma ricorda anche che JavaScript utilizza la compilazione JIT e questo funziona molto male con eval. Eval è un po 'come una blackbox per il compilatore e JavaScript deve essere in grado di prevedere il codice in anticipo (in una certa misura) per applicare in modo sicuro e corretto le ottimizzazioni delle prestazioni e l'ambito. In alcuni casi, l'impatto sulle prestazioni può persino influenzare altri codici al di fuori di eval.

Se vuoi saperne di più: https://github.com/getify/You-Dont-Know-JS/blob/master/scope%20%26%20closures/ch2.md#eval


0

Va bene usarlo se hai il controllo completo sul codice che viene passato alla evalfunzione.


2
Se hai il controllo completo su ciò che stai passando eval, allora la grande domanda diventa: quando ha senso che sia una stringa anziché un vero JS?
cHao,

@cHao Ad esempio, se hai un'applicazione di gioco di grandi dimensioni (5-10 MB di Javascript), è meglio creare prima un AJAX-Preloader a caricamento rapido (1kb), che carica il grande script principale, mentre visualizza un caricamento- Bar o qualcosa di simile. Dopo il download è possibile utilizzare "eval (sorgente)" o meglio "nuova funzione (sorgente)" per eseguire il Game-Application-Script caricato. In questo modo l'utente può vedere visivamente che l'applicazione ha bisogno di tempo per scaricare fino all'avvio del gioco. Senza questo, l'utente deve attendere il caricamento dell'intera Applicazione senza alcun feedback visivo.
SammieFox,

@SammieFox Ci sono altri (e migliori) modi per farlo, in particolare <script async="true" src="...">. Vedi anche: w3bits.com/async-javascript
Ruud Helderman

La risposta è un consiglio pericoloso; troppi sviluppatori hanno un falso senso di avere il controllo. Il consiglio ha un senso per il software che non viene più mantenuto attivamente. Ma tale software dovrebbe essere considerato morto.
Ruud Helderman,

0

Solo durante il test, se possibile. Si noti inoltre che eval () è molto più lento di altri valutatori specializzati JSON ecc.


0

Non c'è motivo di non usare eval () purché si possa essere sicuri che l'origine del codice provenga da te o dall'utente reale. Anche se è in grado di manipolare ciò che viene inviato nella funzione eval (), questo non è un problema di sicurezza, perché è in grado di manipolare il codice sorgente del sito Web e può quindi modificare il codice JavaScript stesso.

Quindi ... quando non usare eval ()? Eval () non dovrebbe essere usato solo quando esiste la possibilità che una terza parte possa cambiarlo. Come intercettare la connessione tra il client e il tuo server (ma se questo è un problema usa HTTPS). Non dovresti eval () per analizzare il codice scritto da altri come in un forum.


Ri "Non c'è motivo di non usare eval () purché tu possa essere sicuro che l'origine del codice provenga da te o dall'utente reale." Questo presuppone che ci sia un singolo utente. Tale premessa non è dichiarata nel PO. Quando ci sono più utenti, trascurato evaldi una stringa composta dal contenuto di un utente può consentire a quell'utente di eseguire il codice nel browser dell'altro utente.
Mike Samuel,

@MikeSamuel, eval può eseguire il codice nel browser di altri utenti, non l'ho sentito, l'hai provato? Questo non è mai successo nella storia della navigazione, puoi mostrarci un esempio?
Akash Kava,

@AkashKava, Una stringa può avere origine con un agente utente, essere archiviata in un database e quindi pubblicata su un altro browser eval. Succede tutto il tempo.
Mike Samuel,

@MikeSamuel database? dove? chi serve una stringa sbagliata? non è colpa del database sul lato server? innanzitutto EVAL non deve essere incolpato di un codice lato server scritto male. Usa jsfiddle e mostra al mondo un esempio reale in cui può causare danni.
Akash Kava,

2
@AkashKava, non capisco la tua domanda. Non stiamo parlando di un'applicazione specifica, ma dei motivi per non usarla eval. In che modo è utile dare la colpa al server? Se qualcuno dovrebbe essere incolpato, dovrebbe essere l'attaccante. Indipendentemente dalla colpa, un client che non è vulnerabile a XSS nonostante i bug nel server è migliore di un client che è vulnerabile, essendo tutti uguali.
Mike Samuel,

0

Se è veramente necessario, eval non è male. Ma il 99,9% degli usi di eval in cui mi imbatto non sono necessari (ad esclusione di roba setTimeout).

Per me il male non è una prestazione o addirittura un problema di sicurezza (beh, indirettamente è entrambi). Tutti questi usi non necessari di eval si aggiungono a un inferno di manutenzione. Gli strumenti di refactoring vengono eliminati. La ricerca del codice è difficile. Gli effetti imprevisti di questi eval sono la legione.


5
eval non è necessario per setTimeout. È possibile utilizzare anche un riferimento di funzione lì.
Matthew Crumley,

0

Quando JavaScript () di eval non è male?

Cerco sempre di scoraggiare l'uso di eval . Quasi sempre, è disponibile una soluzione più pulita e mantenibile. Eval non è necessario nemmeno per l'analisi JSON . Eval aggiunge all'inferno della manutenzione . Non senza motivo, è malvisto da maestri come Douglas Crockford.

Ma ho trovato un esempio in cui dovrebbe essere usato:

Quando è necessario passare l'espressione.

Ad esempio, ho una funzione che costruisce un google.maps.ImageMapTypeoggetto generale per me, ma devo dirgli la ricetta, come dovrebbe costruire l'URL del riquadro dai parametri zoome coord:

my_func({
    name: "OSM",
    tileURLexpr: '"http://tile.openstreetmap.org/"+b+"/"+a.x+"/"+a.y+".png"',
    ...
});

function my_func(opts)
{
    return new google.maps.ImageMapType({
        getTileUrl: function (coord, zoom) {
            var b = zoom;
            var a = coord;
            return eval(opts.tileURLexpr);
        },
        ....
    });
}

3
Sembra che potrebbe essere refactored in modo che eval () non sia necessario - tileURLexpr è solo un modello, quindi un uso giudizioso di replace () farebbe il lavoro. Tuttavia, mi ricorda un esempio che avevo in mente quando ho presentato la domanda, che riguardava il consentire a un utente di specificare una formula matematica da valutare, simile alla funzionalità del foglio di calcolo. Ovviamente non l'ho menzionato in quel momento perché non volevo influenzare le risposte!
Richard Turner,

8
tileURL: function (zoom, coord) { return 'http://tile.openstreetmap.org/' + b + '/' + a.x + '/' + a.y + '.png'; },
Casey Chu,

0

Il mio esempio di utilizzo eval: import .

Di solito è fatto.

var components = require('components');
var Button = components.Button;
var ComboBox = components.ComboBox;
var CheckBox = components.CheckBox;
...
// That quickly gets very boring

Ma con l'aiuto di evale una piccola funzione di aiuto ottiene un aspetto molto migliore:

var components = require('components');
eval(importable('components', 'Button', 'ComboBox', 'CheckBox', ...));

importable potrebbe sembrare (questa versione non supporta l'importazione di membri concreti).

function importable(path) {
    var name;
    var pkg = eval(path);
    var result = '\n';

    for (name in pkg) {
        result += 'if (name !== undefined) throw "import error: name already exists";\n'.replace(/name/g, name);
    }

    for (name in pkg) {
        result += 'var name = path.name;\n'.replace(/name/g, name).replace('path', path);
    }
    return result;
}

2
+1 per l'idea, ma si dispone di un bug qui: .replace(/name/g, name).replace('path', path). Se namecontiene la stringa, "path"potresti ottenere sorprese.
wberry,

1
Dichiarare una variabile per ogni proprietà di componentsè un possibile odore di codice; il refactoring del codice potrebbe eliminare del tutto il "problema". La tua soluzione attuale è solo zucchero sintattico. Se insisti nel farlo, ti consiglio di scrivere il tuo preprocessore, da eseguire prima della distribuzione. Ciò dovrebbe tenere evallontano dal codice di produzione.
Ruud Helderman,

0

Eval non è malvagio, solo abusato.

Se hai creato il codice inserendolo o se ti fidi di esso, va bene. Le persone continuano a parlare di come l'input dell'utente non ha importanza con eval. Beh, una specie di ~

Se c'è l'input dell'utente che va al server, quindi ritorna al client e quel codice viene usato in eval senza essere disinfettato. Complimenti, hai aperto la scatola di Pandora per i dati dell'utente da inviare a chiunque.

A seconda di dove si trova l'Eval, molti siti Web utilizzano SPA e Eval potrebbe rendere più semplice l'accesso dell'utente alle applicazioni interne che altrimenti non sarebbe stato facile. Ora possono creare un'estensione del browser fasulla che può legare in quel codice e rubare di nuovo i dati.

Devo solo capire qual è il punto di te usando l'Eval. Generare codice non è proprio l'ideale quando puoi semplicemente creare metodi per fare quel genere di cose, usare oggetti o simili.

Ora un bell'esempio di utilizzo di eval. Il tuo server sta leggendo il file swagger che hai creato. Molti dei parametri URL vengono creati nel formato {myParam}. Quindi ti piacerebbe leggere gli URL e poi convertirli in stringhe di modello senza dover effettuare sostituzioni complesse perché hai molti endpoint. Quindi potresti fare qualcosa del genere. Nota che questo è un esempio molto semplice.

const params = { id: 5 };

const route = '/api/user/{id}';
route.replace(/{/g, '${params.');

// use eval(route); to do something

-1

Generazione del codice. Di recente ho scritto una libreria chiamata Hyperbars che colma il divario tra virtual-dom e manubrio . Lo fa analizzando un modello di manubrio e convertendolo in iperscript . L'iperscript viene generato prima come stringa e prima di restituirlo, eval()per trasformarlo in codice eseguibile. ho trovatoeval() in questa particolare situazione l'esatto contrario 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 sono un problema anche in una situazione come questa perché è necessario interpretare la stringa generata una sola volta e riutilizzare più volte l'output eseguibile.

Puoi vedere come è stata raggiunta la generazione del codice se sei curioso qui .


"L'iperscript viene generato prima come stringa (...)" Ha più senso eseguire tutta la generazione di codice in fase di compilazione, scrivere il codice iperscript risultante in un file eseguibile (.js) separato, quindi distribuirlo per testare e produzione. Adoro il modo in cui usi la generazione del codice. È solo evalun indizio che alcune responsabilità che appartengono al momento della compilazione sono passate al runtime.
Ruud Helderman,

-1

La mia convinzione è che eval sia una funzione molto potente per applicazioni web lato client e sicura ... Sicuro come JavaScript, che non lo sono. :-) I problemi di sicurezza sono essenzialmente un problema lato server perché, ora, con uno strumento come Firebug, puoi attaccare qualsiasi applicazione JavaScript.


1
L'uso di evaldeve essere protetto dagli attacchi XSS, che non è sempre facile da ottenere.
Benjamin,

-1

Eval è utile per la generazione di codice quando non si dispone di macro.

Ad esempio (uno stupido), se stai scrivendo un compilatore Brainfuck , probabilmente vorrai costruire una funzione che esegue la sequenza di istruzioni come una stringa e valutarla per restituire una funzione.


O scrivi un compilatore (che salva anziché eseguire il codice generato) o scrivi un interprete (dove ogni istruzione ha un'implementazione precompilata). Né è un caso d'uso per eval.
Ruud Helderman,

Se hai generato il codice javascript e volessi eseguirlo immediatamente (diciamo per i vantaggi in termini di prestazioni rispetto all'interpretazione diretta), sarebbe un caso d'uso per eval.
Erik Haliewicz,

Buon punto; Ho visto un esempio in questo articolo su Blockly . Sono scioccato da Google eval, quando l'alternativa ( Funzione ) è più veloce ( come spiegato in MDN ) e più affidabile (previene i bug imprevedibili attraverso un migliore isolamento tra il codice generato e altri codici "di supporto" sulla stessa pagina Web).
Ruud Helderman,

-5

Quando si analizza una struttura JSON con una funzione di analisi (ad esempio, jQuery.parseJSON), si aspetta una struttura perfetta del file JSON (ogni nome di proprietà è tra virgolette). Tuttavia, JavaScript è più flessibile. Pertanto, è possibile utilizzare eval () per evitarlo.


4
Non usare ciecamente eval, esp. quando si ottengono dati JSON da una fonte di terze parti. Vedi JSON.Stringify senza virgolette sulle proprietà? per l'approccio corretto per analizzare "JSON senza virgolette".
Rob W,

2
Se non utilizza virgolette doppie attorno ai nomi delle proprietà, potrebbe essere una rappresentazione in formato stringa di un oggetto letterale, ma non è JSON . JSON definisce i nomi delle proprietà come a stringe definisce a stringcome una sequenza di zero o più caratteri Unicode, racchiusi tra virgolette doppie, utilizzando escape di barra rovesciata.
Codice inutile

Vedi articolo di Nikolas Zakas - "eval () non è male, solo frainteso" nczonline.net/blog/2013/06/25/eval-isnt-evil-just-misunderstood
vitmalina

@vitmalina Dall'articolo di Zakas: "Questo può essere pericoloso se stai prendendo l'input dell'utente e lo esegui attraverso eval (). Tuttavia, se il tuo input non è dell'utente, c'è qualche vero pericolo?" Questo è esattamente il problema. Una volta che il tuo codice supera le proporzioni di "ciao mondo", diventa rapidamente impossibile dimostrare che non stai perdendo l'input dell'utente eval. In qualsiasi seria applicazione web multi-tenant, con dozzine di sviluppatori che lavorano sulla stessa base di codice, questo è inaccettabile.
Ruud Helderman,
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.