298 votes

Quand la fonction eval() de JavaScript n'est-elle pas mauvaise ?

J'écris un code JavaScript pour analyser les fonctions saisies par l'utilisateur (pour une fonctionnalité de type feuille de calcul). Après avoir analysé la formule, je pourrait le convertir en JavaScript et l'exécuter eval() sur elle pour obtenir le résultat.

Cependant, j'ai toujours évité d'utiliser eval() si je peux l'éviter, car c'est un mal (et, à tort ou à raison, j'ai toujours pensé que c'est encore plus mal en JavaScript, car le code à évaluer peut être modifié par l'utilisateur).

Alors, quand peut-on l'utiliser ?

7 votes

La plupart des bibliothèques JSON n'utilisent pas, en fait, eval sous le capot, exactement pour se protéger contre les risques de sécurité.

13 votes

@Sean - JQuery et Prototype utilisent tous deux eval (JQuery l'utilise via new Function).

8 votes

@plodder - D'où tenez-vous vos informations ? jQuery utilise la fonction native JSON.parse() depuis la version 1.4 (en 2010) ! Voyez par vous-même : code.jquery.com/jquery-1.4.js

284voto

user27476 Points 1544

J'aimerais prendre un moment pour répondre à la prémisse de votre question - que eval() est " maléfique ". Le mot " maléfique Le terme "dangereux", tel qu'il est utilisé par les personnes travaillant dans les langages de programmation, signifie généralement "dangereux", ou plus précisément "capable de causer beaucoup de dégâts avec une commande d'apparence simple". Alors, quand est-il acceptable d'utiliser quelque chose de dangereux ? Quand vous savez quel est le danger et quand vous prenez les précautions appropriées.

Pour en venir au fait, examinons les dangers de l'utilisation de eval(). Il existe probablement de nombreux petits dangers cachés, comme pour tout le reste, mais les deux grands risques - la raison pour laquelle eval() est considéré comme un mal - sont les performances et l'injection de code.

  • Performance - eval() exécute l'interpréteur/compilateur. Si votre code est compilé, c'est un gros problème, car vous devez appeler un compilateur potentiellement lourd au milieu de l'exécution. Cependant, JavaScript est encore principalement un langage interprété, ce qui signifie que l'appel à eval() n'est pas un gros problème de performance dans le cas général (mais voir mes remarques spécifiques ci-dessous).
  • Injection de code - eval() exécute potentiellement une chaîne de code sous des privilèges élevés. Par exemple, un programme exécuté en tant qu'administrateur/Root ne voudra jamais exécuter eval() une entrée utilisateur, car cette entrée pourrait être "rm -rf /etc/important-file" ou pire. Encore une fois, JavaScript dans un navigateur n'a pas ce problème, parce que le programme est exécuté dans le propre compte de l'utilisateur de toute façon. Le JavaScript côté serveur pourrait avoir ce problème.

Venons-en à votre cas spécifique. D'après ce que j'ai compris, vous générez les chaînes vous-même, donc en supposant que vous faites attention à ne pas permettre à une chaîne comme "rm -rf quelque chose d'important" d'être générée, il n'y a pas de risque d'injection de code (mais n'oubliez pas que c'est le cas de très très dur pour s'en assurer dans le cas général). De plus, si vous vous exécutez dans le navigateur, l'injection de code est un risque assez mineur, je crois.

Pour ce qui est des performances, vous devrez les comparer à la facilité de codage. Je pense que si vous analysez la formule, vous pouvez tout aussi bien calculer le résultat pendant l'analyse plutôt que de lancer un autre analyseur (celui qui se trouve dans eval()). Mais il peut être plus facile de coder en utilisant eval(), et l'impact sur les performances sera probablement imperceptible. Il semble que eval() dans ce cas ne soit pas plus maléfique que toute autre fonction qui pourrait éventuellement vous faire gagner du temps.

82 votes

Vous n'abordez pas le problème du code qui utilise eval qui est difficile à déboguer.

0 votes

Vous trouverez une réponse plus complète à cette question ici. stackoverflow.com/questions/951373/when-is-eval-evil-in-php

56 votes

L'injection de code est un problème très sérieux pour le javascript si vous êtes un tant soit peu concerné par les données de vos utilisateurs. Le code injecté s'exécutera (dans le navigateur) comme s'il provenait de votre site, ce qui lui permettra de faire toutes sortes de manipulations que l'utilisateur pourrait faire manuellement. Si vous autorisez un code (tiers) à entrer dans votre page, il peut commander des choses au nom de votre client, ou changer son gravatar, ou tout ce qu'il pourrait faire via votre site. Soyez très prudent. Laisser les pirates s'approprier vos clients est aussi grave que de laisser votre serveur leur appartenir.

79voto

Shog9 Points 82052

eval() n'est pas mauvais. Ou, si c'est le cas, c'est un mal de la même manière que la réflexion, les entrées/sorties de fichiers/réseaux, le threading et l'IPC sont "mauvais" dans d'autres langages.

Si, pour votre objectif , eval() est plus rapide qu'une interprétation manuelle, ou rend votre code plus simple, ou plus clair... alors vous devriez l'utiliser. Si ce n'est ni l'un ni l'autre, alors vous ne devez pas le faire. C'est aussi simple que cela.

6 votes

L'un de ces objectifs pourrait être de générer un code optimisé qui serait soit trop long, soit trop répétitif pour être écrit à la main. Le genre de choses qui, en LISP, nécessiterait une macro.

9 votes

Ce conseil est tellement général qu'il pourrait être appliqué à n'importe quel bloc de code existant. Il n'apporte vraiment rien à cette question ; en particulier, il n'aide pas ceux qui viennent ici à déterminer si leur utilisation particulière est problématique ou non.

7 votes

Plus rapide, plus simple, plus clair... Cette réponse ne couvre pas assez bien les implications en matière de sécurité.

64voto

Tomalak Points 150423

Quand vous faites confiance à la source.

Dans le cas de JSON, il est plus ou moins difficile d'altérer la source, car elle provient d'un serveur web que vous contrôlez. Tant que le JSON lui-même ne contient pas de données téléchargées par un utilisateur, il n'y a pas d'inconvénient majeur à utiliser eval.

Dans tous les autres cas, je ferais tout mon possible pour m'assurer que les données fournies par l'utilisateur sont conformes à mes règles avant de les transmettre à eval().

14 votes

Une chaîne json doit toujours être testée par rapport à la grammaire json avant d'être utilisée dans eval(). Ainsi, la chaîne json "{foo:alert('XSS')}" ne passerait pas puisque "alert('XSS')" n'est pas une valeur correcte.

0 votes

Ou lorsque l'environnement est sécurisé.

0 votes

Mais peut-on vraiment faire confiance à la source lorsque l'on utilise un protocole susceptible de subir des attaques de type "man-in-the-middle" ?

26voto

plodder Points 1307

Soyons réalistes, les amis :

  1. Tous les principaux navigateurs disposent désormais d'une console intégrée que le pirate en herbe peut utiliser abondamment pour invoquer n'importe quelle fonction avec n'importe quelle valeur - pourquoi se donnerait-il la peine d'utiliser une instruction eval, même s'il le pouvait ?

  2. S'il faut 0,2 seconde pour compiler 2000 lignes de JavaScript, quelle est la dégradation de mes performances si j'évalue quatre lignes de JSON ?

Même l'explication de Crockford pour "l'ovale est le mal" est faible.

eval est diabolique, La fonction eval est la fonction la plus mal utilisée de l'interface utilisateur. JavaScript. Évitez-la

Comme Crockford lui-même pourrait dire "Ce genre de déclaration tend à générer une névrose irrationnelle. Ne l'achetez pas."

Comprendre l'évaluation et savoir quand elle peut être utile est bien plus important. Par exemple, eval est un outil judicieux pour évaluer les réponses du serveur qui ont été générées par votre logiciel.

BTW : Prototype.js appelle eval directement cinq fois (y compris dans evalJSON() et evalResponse()). jQuery l'utilise dans parseJSON (via le constructeur Function).

10 votes

JQuery utilise la fonction JSON.parse intégrée du navigateur si elle est disponible (ce qui est beaucoup plus rapide et plus sûr), en utilisant eval uniquement comme mécanisme de secours. L'affirmation "eval est le mal" est une ligne directrice raisonnablement bonne.

37 votes

Re "Tous les principaux navigateurs ont maintenant une console intégrée...". L'injection de code est un problème lorsqu'un utilisateur peut entrer du code qui est ensuite exécuté dans le navigateur d'un autre utilisateur. Les consoles de navigateur ne permettent pas à elles seules à un utilisateur d'exécuter du code dans le navigateur d'un autre utilisateur. Elles ne sont donc pas pertinentes pour décider s'il vaut la peine de se protéger contre l'injection de code.

34 votes

"Tous les principaux navigateurs ont maintenant une console intégrée... pourquoi se donneraient-ils la peine d'utiliser une instruction eval ?" - Vous êtes loin du compte. Je vous suggère de modifier votre réponse. La capacité d'un utilisateur à injecter du code qui peut s'exécuter dans le navigateur d'un autre est un problème majeur. Et c'est là que vous devez devenir vraiment réel.

19voto

swilliams Points 19415

J'ai tendance à suivre Le conseil de Crockford para eval() et l'éviter complètement. Même les méthodes qui semblent l'exiger ne le sont pas. Par exemple, le setTimeout() vous permet de passer une fonction plutôt que eval.

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

Même si c'est un de confiance je ne l'utilise pas, car le code renvoyé par JSON peut être confus, ce qui pourrait, au mieux, faire quelque chose de louche, au pire, exposer quelque chose de mauvais.

1 votes

Comment un appel réussi à un serveur web peut-il produire un résultat confus (malgré les bogues dans le code du serveur web générant le JSON) ?

2 votes

Je pense que les bogues dans le formateur JSON du côté serveur sont certainement un problème. La réponse du serveur dépend-elle d'un texte soumis par l'utilisateur ? Alors vous devez faire attention aux XSS.

3 votes

Si votre serveur web n'est pas authentifié via HTTPS, vous risquez de subir une sorte d'attaque de type "man-in-the-middle" au cours de laquelle un autre hôte intercepte la demande et envoie ses propres données.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X