Pourquoi l'utilisation de la fonction eval JavaScript est-elle une mauvaise idée?

la fonction eval est un moyen puissant et facile de générer dynamiquement du code, alors quelles sont les mises en garde?

480
demandé sur Nisarg Shah 2008-09-17 23:09:54
la source

25 ответов

  1. L'usage impropre de eval ouvre votre code pour les attaques par injection

  2. débogage peut être plus difficile (pas de numéro de ligne, etc.)

  3. le code eval'd s'exécute plus lentement (aucune possibilité de compiler/cacher le code eval'd)

Edit: comme @ Jeff Walden le souligne dans les commentaires, #3 est de moins en moins vrai aujourd'hui qu'il ne l'était en 2008. Cependant, bien que certaines mises en cache de scripts compilés puissent se produire, ceci ne sera limité qu'aux scripts qui sont évalués et répétés sans aucune modification. Un scénario plus probable est que vous êtes en train d'évaluer des scripts qui ont subi de légères modifications à chaque fois et en tant que tel ne pouvaient pas être mis en cache. Disons qu'un code d'évaluation s'exécute plus lentement.

357
répondu Prestaul 2017-09-10 02:12:15
la source

eval n'est pas toujours mauvais. Il y a des moments où c'est parfaitement approprié.

cependant, eval est actuellement et historiquement massivement sur-utilisé par les gens qui ne savent pas ce qu'ils font. Cela inclut les personnes qui écrivent des tutoriels JavaScript, malheureusement, et dans certains cas cela peut avoir des conséquences sur la sécurité - ou, plus souvent, de simples bogues. Donc, plus nous pouvons faire pour jeter un point d'interrogation sur eval, mieux c'est. Chaque fois que vous utilisez eval vous devez vérifier la santé mentale ce que vous faites, parce qu'il y a des chances que vous le fassiez d'une manière meilleure, plus sûre et plus propre.

Pour donner un trop typique exemple, pour définir la couleur d'un élément avec un id stocké dans la variable 'pommes de terre':

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

si les auteurs du genre de code ci-dessus avaient une idée des bases du fonctionnement des objets JavaScript, ils se seraient rendus compte que les crochets peuvent être utilisés à la place des noms de points littéraux, évitant ainsi la nécessité d'eval:

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

...ce qui est beaucoup plus facile à lire ainsi que potentiellement moins buggé.

(mais alors, quelqu'un qui / vraiment / savait ce qu'il faisait dirait:

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

, qui est plus fiable que le vieux tour douteux d'accéder aux éléments DOM directement à partir de l'objet document.)

336
répondu bobince 2013-03-02 19:50:43
la source

je crois que c'est parce qu'il peut exécuter n'importe quelle fonction JavaScript à partir d'une chaîne de caractères. En l'utilisant, il est plus facile pour les gens d'injecter du code rogue dans l'application.

35
répondu kemiller2002 2012-04-08 20:52:47
la source

deux points me viennent à l'esprit:

  1. "151900920 de Sécurité" (mais aussi longtemps que vous générez de la chaîne à être évaluée vous-même, cela pourrait être un non-problème)

  2. Performance: jusqu'à ce que le code à exécuter soit inconnu, il ne peut pas être optimisé. (sur javascript et la performance, certainement présentation de Steve Yegge )

25
répondu xtofl 2008-09-17 23:20:52
la source

passer l'entrée de l'utilisateur à eval() est un risque de sécurité, mais aussi chaque invocation d'eval () crée une nouvelle instance de L'interpréteur JavaScript. Cela peut être un porc de ressource.

20
répondu Andrew Hedges 2008-09-17 23:28:20
la source

c'est généralement seulement un problème si vous passez eval user input.

17
répondu Mark Biek 2008-09-17 23:12:59
la source

principalement, c'est beaucoup plus difficile à maintenir et à déboguer. C'est comme un goto . Vous pouvez l'utiliser, mais il est plus difficile de trouver des problèmes et plus difficile pour les gens qui peuvent avoir besoin d'apporter des changements plus tard.

15
répondu Brian 2012-04-08 20:55:19
la source

une chose à garder à l'esprit est que vous pouvez souvent utiliser eval() pour exécuter du code dans un environnement autrement restreint - les sites de réseaux sociaux qui bloquent des fonctions JavaScript spécifiques peuvent parfois être dupé en les brisant dans un bloc eval -

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

donc si vous cherchez à lancer un code JavaScript où il pourrait ne pas être autorisé autrement ( Myspace , je vous regarde...) alors la fonction eval() peut être un bon truc.

Cependant, pour toutes les raisons mentionnées ci - dessus, vous ne devriez pas l'utiliser pour votre propre code, où vous avez le contrôle complet-ce n'est tout simplement pas nécessaire, et mieux-relégué à L'étagère 'rusé JavaScript hacks'.

13
répondu matt lohkamp 2014-09-12 01:31:59
la source

sauf si vous laissez eval() un contenu dynamique (via cgi ou input), il est aussi sûr et solide que tous les autres JavaScript dans votre page.

11
répondu Thevs 2013-11-04 22:33:54
la source

avec le reste des réponses, Je ne pense pas que les énoncés eval puissent avoir une minimisation avancée.

7
répondu Paul Mendoza 2012-01-03 07:52:47
la source

c'est un risque de sécurité possible, il a une portée d'exécution différente, et est très inefficace, car il crée un environnement de script entièrement nouveau pour l'exécution du code. Voir ici pour plus d'informations: eval .

Il est très utile, cependant, et utilisé avec modération peut ajouter beaucoup de bonnes fonctionnalités.

6
répondu Tom 2013-10-31 17:34:29
la source

sauf si vous êtes sûr à 100% que le code évalué provient d'une source fiable (généralement votre propre application), alors c'est un moyen infaillible d'exposer votre système à une attaque de script intersite.

5
répondu John Topley 2008-09-17 23:13:53
la source

je sais que cette discussion est ancienne, mais j'aime vraiment cette approche par Google et je voulais partager ce sentiment avec d'autres;)

l'autre chose est que plus vous obtenez le plus vous essayez de comprendre et finalement vous ne croyez pas que quelque chose est bon ou mauvais juste parce que quelqu'un l'a dit :) Il s'agit d'une très inspirante vidéo qui m'a aidé à penser plus par moi-même:) les bonnes pratiques sont bonnes, mais ne le faites pas utiliser mindelessly :)

5
répondu op1ekun 2012-11-30 03:00:33
la source

il réduit considérablement votre niveau de confiance en matière de sécurité.

4
répondu David Plumpton 2008-09-18 00:06:41
la source

si vous voulez que l'utilisateur entre quelques fonctions logiques et d'évaluer pour et le ou alors la fonction eval JavaScript est parfait. Je peux accepter deux cordes et eval(uate) string1 === string2 , etc.

4
répondu Ian 2012-04-08 21:18:51
la source

ce n'est pas nécessairement mauvais si vous savez dans quel contexte vous l'utilisez.

si votre application utilise eval() pour créer un objet à partir d'un JSON qui est revenu d'une XMLHttpRequest sur votre propre site, créé par votre code de confiance côté serveur, ce n'est probablement pas un problème.

le code JavaScript non fiable côté client ne peut pas faire grand chose de toute façon. À condition que la chose que vous exécutez eval() ça vient d'une source raisonnable, tu vas bien.

4
répondu MarkR 2018-03-13 06:48:25
la source

si vous repérez l'utilisation d'eval() dans votre code, souvenez-vous du mantra "eval() est mauvais."

This la fonction prend une chaîne de caractères arbitraire et l'exécute sous forme de code JavaScript. Lorsque le code de la la question est connue à l'avance (non déterminée à l'exécution), il n'y a aucune raison d'utiliser la fonction eval(). Si le code est généré dynamiquement à l'exécution, il y a souvent une meilleure façon de atteindre le but sans eval(). Par exemple, il suffit d'utiliser la notation de crochet carré pour accès dynamique propriétés est mieux et plus simple:

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

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

L'utilisation de eval() a également des implications de sécurité, car vous pourriez être en train d'exécuter le code (pour exemple provenant du réseau) qui a été falsifié. Il s'agit d'un anti-modèle courant lorsqu'il s'agit d'une réponse JSON d'une requête Ajax. Dans ces cas il est préférable d'utiliser les méthodes intégrées des navigateurs pour analyser la réponse JSON pour faire assurer qu'il est sécuritaire et valide. Pour les navigateurs qui ne prennent pas en charge JSON.parse() nativement, vous pouvez utilisez une bibliothèque de JSON.org.

il est également important de se rappeler que passer des cordes à setInterval() , setTimeout() , et le constructeur Function() est, pour la plupart, similaire à l'utilisation de eval() et donc doit être évitée.

dans les coulisses, JavaScript doit encore évaluer et exécuter la chaîne que vous passez comme code de programmation:

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

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

utilisant le nouveau constructeur de fonction () est similaire à eval () et doit être approché avec des soins. Il peut s'agir d'une construction puissante, mais elle est souvent utilisée à mauvais escient. Si vous devez absolument utiliser eval() , vous pouvez envisager d'utiliser la nouvelle Fonction() à la place.

Il ya un petit potentiel avantage parce que le code évalué dans la nouvelle fonction () sera exécuté dans une fonction locale portée, de sorte que toute variable définie avec var dans le code évalué ne deviendra pas globals automatiquement.

un autre chemin pour éviter automatique globals est d'envelopper le eval() appel dans une fonction immédiate.

3
répondu 12345678 2017-05-08 17:06:35
la source

outre les problèmes de sécurité possibles si vous exécutez du code soumis par l'utilisateur, la plupart du temps il y a un meilleur moyen qui n'implique pas re-parsing le code chaque fois qu'il est exécuté. Les fonctions anonymes ou les propriétés des objets peuvent remplacer la plupart des utilisations d'eval et sont beaucoup plus sûres et plus rapides.

2
répondu Matthew Crumley 2008-09-17 23:14:49
la source

cela pourrait devenir plus problématique à mesure que la prochaine génération de navigateurs sortent avec une certaine saveur de compilateur JavaScript. Le Code exécuté via Eval peut ne pas fonctionner aussi bien que le reste de votre JavaScript contre ces nouveaux navigateurs. Quelqu'un devrait faire certains profils.

2
répondu brian 2008-09-17 23:20:41
la source

c'est un des bons articles qui parle d'eval et comment ce n'est pas un mal: http://www.nczonline.net/blog/2013/06/25/eval-isnt-evil-just-misunderstood/

Je ne dis pas que tu devrais t'enfuir et commencer à utiliser eval() partout. En fait, il ya très peu de cas de bonne utilisation pour exécuter la fonction eval (). Il y a certainement des préoccupations quant à la clarté du code, la fiabilité, et certainement la performance qui ne devrait pas être négliger. Mais vous ne devriez pas avoir peur de l'utiliser lorsque vous avez un cas où la fonction eval() de sens. Essaie de ne pas l'utiliser d'abord, mais ne laisse personne t'effrayer. vous pensez que votre code est plus fragile ou moins sûr() est utilisé de façon appropriée.

2
répondu Amr Elgarhy 2014-10-08 13:04:57
la source

eval () est très puissant et peut être utilisé pour exécuter une instruction JS ou évaluer une expression. Mais la question n'est pas sur les utilisations de eval() mais disons simplement comment la chaîne que vous utilisez avec eval() est affectée par une partie malveillante. À la fin, vous lancerez du code malveillant. Avec le pouvoir vient une grande responsabilité. Alors utilisez-le sagement si vous l'utilisez. Ceci n'est pas très lié à la fonction eval() mais cet article a de bonnes informations: http://blogs.popart.com/2009/07/javascript-injection-attacks / Si vous cherchez les bases d'eval() regardez ici: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval

2
répondu genius 2014-10-25 19:17:51
la source

le moteur JavaScript présente un certain nombre d'optimisations de performances qu'il réalise pendant la phase de compilation. Certains d'entre eux se résument à être en mesure d'analyser essentiellement statiquement le code au fur et à mesure qu'il s'exécute, et de pré-déterminer où se trouvent toutes les déclarations de variables et de fonctions, de sorte qu'il faut moins d'efforts pour résoudre les identificateurs au cours de l'exécution.

mais si le moteur trouve une eval(..) dans le code, il doit essentiellement supposer que toute sa conscience de l'emplacement de l'identifiant peut ne pas être valide, car il ne peut pas savoir au moment de lexing exactement quel code vous pouvez passer à eval(.. pour modifier la portée lexicale, ou le contenu de l'objet vous pouvez passer à créer une nouvelle portée lexicale d'être consultés.

en d'autres termes, dans le sens pessimiste, la plupart des optimisations qu'il ferait sont inutiles si éval(..) est présent, de sorte qu'il ne réalise tout simplement pas les optimisations du tout.

ça explique tout.

référence:

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

1
répondu hkasera 2016-01-30 09:34:03
la source

ce n'est pas toujours une mauvaise idée. Prenez par exemple la génération de code. J'ai récemment écrit une bibliothèque appelée hyperbares qui fait le pont entre dom virtuel et guidon . Pour ce faire, il analyse un modèle de guidon et le convertit en hyperscript qui est ensuite utilisé par virtual-dom. L'hyperscript est généré comme une chaîne de caractères en premier et avant de le retourner, eval() il à le transformer en code exécutable. J'ai trouvé eval() dans cette situation le contraire exact du mal.

en gros à partir de

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

à ce

(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({}))

la performance de eval() n'est pas un problème dans une situation comme celle-ci parce que vous n'avez besoin d'interpréter la chaîne générée qu'une fois et de réutiliser plusieurs fois la sortie exécutable.

Vous pouvez voir comment le code génération a été atteint si vous êtes curieux ici .

1
répondu Wikened 2017-03-30 11:44:15
la source

j'irais jusqu'à dire qu'il n'a pas vraiment d'importance si vous utilisez eval() en javascript qui fonctionne dans les navigateurs.*(opposition)

tous les navigateurs modernes ont une console de développeur où vous pouvez exécuter JavaScript arbitraire de toute façon et n'importe quel développeur semi-intelligent peut regarder votre source JS et mettre n'importe quels bits de celui-ci dont ils ont besoin dans la console de développement pour faire ce qu'ils veulent.

* aussi longtemps que les paramètres de votre serveur ont la validation correcte & assainissement des valeurs fournies par l'utilisateur, il ne devrait pas se soucier de ce qui est analysé et évalué dans votre javascript côté client.

si vous deviez demander s'il est approprié d'utiliser eval() en PHP cependant, la réponse est Non , à moins que vous whitelist toutes les valeurs qui peuvent être passées à votre déclaration eval.

1
répondu Adam Copley 2018-03-01 14:30:39
la source

Je n'essaierai pas de réfuter quoi que ce soit dit auparavant, mais je proposerai cette utilisation d'eval() qui (autant que je sache) ne peut pas être fait d'une autre manière. Il y a probablement d'autres façons de coder ceci, et probablement des façons de l'optimiser, mais cela se fait à la main et sans aucune sonnerie et sifflements pour des raisons de clarté pour illustrer une utilisation d'eval qui n'a vraiment pas d'autres alternatives. C'est-à-dire: des noms d'objets créés de manière dynamique (ou plus précisément) (par opposition à des valeurs).

//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);

EDIT: en passant, je ne dirais pas (pour l'ensemble des raisons de sécurité, a souligné jusqu'ici) que vous basez-vous des noms d'objets sur la saisie de l'utilisateur. Je ne peux penser à aucune bonne raison pour laquelle vous voulez le faire bien. Pourtant, j'ai pensé que je le ferais remarquer que ce ne serait pas une bonne idée:)

0
répondu Carnix 2015-02-12 21:45:04
la source

Autres questions sur javascript security eval