J'écris du code JavaScript pour analyser les fonctions entrées par l'utilisateur (pour les fonctionnalités de type tableur). Après avoir analysé la formule, je pouvais le convertir en JavaScript et l'exécuter eval()
pour donner le résultat.
Cependant, j'ai toujours hésité à l'utiliser eval()
si je peux l'éviter parce que c'est mal (et, à tort ou à raison, j'ai toujours pensé que c'était encore plus mal en JavaScript, car le code à évaluer pourrait être modifié par l'utilisateur ).
Alors, quand c'est OK de l'utiliser?
javascript
coding-style
eval
Richard Turner
la source
la source
Réponses:
Je voudrais prendre un moment pour répondre à la prémisse de votre question - que eval () est " diabolique ". Le mot " evil ", tel qu'il est utilisé par les gens du langage de programmation, signifie généralement "dangereux", ou plus précisément "capable de causer beaucoup de mal avec une commande simple". Alors, quand est-ce OK d'utiliser quelque chose de dangereux? Lorsque vous savez quel est le danger et lorsque vous prenez les précautions appropriées.
Au point, regardons les dangers de l'utilisation de eval (). Il y a probablement beaucoup de petits dangers cachés comme tout le reste, mais les deux gros risques - la raison pour laquelle eval () est considéré comme mauvais - sont les performances et l'injection de code.
Passons à votre cas spécifique. D'après ce que je comprends, vous générez les chaînes vous-même, donc en supposant que vous faites attention à ne pas générer une chaîne comme "rm -rf quelque chose d'important", il n'y a pas de risque d'injection de code (mais n'oubliez pas, c'est très très difficile à garantir dans le cas général). De plus, si vous utilisez le navigateur, l'injection de code est un risque assez mineur, je crois.
En ce qui concerne les performances, vous devrez les comparer à la facilité de codage. À mon avis, si vous analysez la formule, vous pourriez aussi bien calculer le résultat pendant l'analyse plutôt que d'exécuter un autre analyseur (celui à l'intérieur de eval ()). Mais il peut être plus facile de coder en utilisant eval (), et les performances seront probablement imperceptibles. Il semble que eval () dans ce cas n'est pas plus mauvais que n'importe quelle autre fonction qui pourrait éventuellement vous faire gagner du temps.
la source
eval()
partir de votre serveur, il pourrait aussi simplement changer la source de la page en premier lieu, et également prendre le contrôle des informations de l'utilisateur. . . Je ne vois pas la différence.eval()
n'est pas mal. Ou, si c'est le cas, c'est mauvais de la même manière que la réflexion, les E / S de fichier / réseau, le filetage et IPC sont "mauvais" dans d'autres langues.Si, pour votre objectif ,
eval()
est plus rapide que l'interprétation manuelle, ou rend votre code plus simple, ou plus clair ... alors vous devriez l'utiliser. Si ni l'un ni l'autre, vous ne devriez pas. Aussi simple que cela.la source
Lorsque vous faites confiance à la source.
Dans le cas de JSON, il est plus ou moins difficile de falsifier la source, car il provient d'un serveur Web que vous contrôlez. Tant que le JSON lui-même ne contient aucune donnée téléchargée par un utilisateur, il n'y a pas d'inconvénient majeur à utiliser eval.
Dans tous les autres cas, je ferais beaucoup d'efforts pour m'assurer que les données fournies par l'utilisateur sont conformes à mes règles avant de les envoyer à eval ().
la source
eval
n'analysera pas non plus correctement toutes les chaînes JSON valides. Par exemple,JSON.parse(' "\u2028" ') === "\u2028"
maiseval(' "\u2028" ')
lève une exception car U + 2028 est une nouvelle ligne en JavaScript mais ce n'est pas une nouvelle ligne en ce qui concerne JSON.Mettons-nous de vrais gens:
Chaque navigateur majeur dispose désormais d'une console intégrée que votre pirate potentiel peut utiliser en abondance pour invoquer n'importe quelle fonction de n'importe quelle valeur - pourquoi s'embêter à utiliser une instruction eval - même s'il le pouvait?
S'il faut 0,2 seconde pour compiler 2000 lignes de JavaScript, quelle est ma dégradation des performances si j'évalue quatre lignes de JSON?
Même l'explication de Crockford pour «eval is evil» est faible.
Comme Crockford lui-même pourrait le dire "Ce genre de déclaration a tendance à générer une névrose irrationnelle. Ne l'achetez pas."
Comprendre eval et savoir quand il pourrait être utile est beaucoup 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).
la source
J'ai tendance à suivre les conseils de Crockford pour
eval()
et éviter complètement. Même les moyens qui semblent l'exiger ne le font pas. Par exemple, lesetTimeout()
vous permet de passer une fonction plutôt que eval.Même s'il s'agit d'une source fiable , je ne l'utilise pas, car le code renvoyé par JSON peut être tronqué, ce qui pourrait au mieux faire quelque chose de chancelant, au pire, exposer quelque chose de mauvais.
la source
J'ai vu des gens préconiser de ne pas utiliser eval, parce que c'est mal , mais j'ai vu les mêmes personnes utiliser Function et setTimeout dynamiquement, alors ils utilisent eval sous les hottes : D
BTW, si votre sandbox n'est pas assez sûr (par exemple, si vous travaillez sur un site qui autorise l'injection de code) eval est le dernier de vos problèmes. La règle de sécurité de base est que toutes les entrées sont mauvaises, mais dans le cas de JavaScript, même JavaScript lui-même peut être mauvais, car en JavaScript, vous pouvez remplacer n'importe quelle fonction et vous ne pouvez pas être sûr d'utiliser la vraie, donc, si un code malveillant démarre avant vous, vous ne pouvez faire confiance à aucune fonction intégrée JavaScript: D
Maintenant, l'épilogue de ce post est:
Si vous en avez VRAIMENT besoin (80% du temps, l'eval n'est PAS nécessaire) et que vous êtes sûr de ce que vous faites, utilisez simplement eval (ou une meilleure fonction;)), les fermetures et la POO couvrent les 80/90% des cas où eval peut être remplacé en utilisant un autre type de logique, le reste est du code généré dynamiquement (par exemple, si vous écrivez un interprète) et comme vous l'avez déjà dit évaluer JSON (ici vous pouvez utiliser l'évaluation sûre de Crockford;))
la source
Eval est complémentaire à la compilation qui est utilisée dans le modèle du code. Par modèle, je veux dire que vous écrivez un générateur de modèle simplifié qui génère un code de modèle utile qui augmente la vitesse de développement.
J'ai écrit un cadre, où les développeurs n'utilisent pas EVAL, mais ils utilisent notre cadre et à son tour ce cadre doit utiliser EVAL pour générer des modèles.
Les performances d'EVAL peuvent être améliorées en utilisant la méthode suivante; au lieu d'exécuter le script, vous devez renvoyer une fonction.
Il devrait être organisé comme
La mise en cache f améliorera certainement la vitesse.
Chrome permet également de déboguer de telles fonctions très facilement.
En ce qui concerne la sécurité, utiliser eval ou non ne fera guère de différence,
Si votre sécurité côté serveur est suffisamment solide pour que quiconque puisse attaquer de n'importe où, vous ne devriez pas vous soucier d'EVAL. Comme je l'ai mentionné, si EVAL n'existait pas, les attaquants ont de nombreux outils pour pirater votre serveur indépendamment de la capacité EVAL de votre navigateur.
Eval ne sert qu'à générer des modèles pour effectuer un traitement de chaîne complexe basé sur quelque chose qui n'est pas utilisé à l'avance. Par exemple, je préférerai
Par opposition à
Comme mon nom d'affichage, qui peut provenir d'une base de données et qui n'est pas codé en dur.
la source
function (first, last) { return last + ' ' + first }
.eval
est principalement d' autres utilisateurs . Supposons que vous ayez une page de paramètres et qu'elle vous permette de définir la façon dont votre nom apparaîtra aux autres. Disons également que vous ne pensiez pas très clairement lorsque vous l'avez écrit, donc votre boîte de sélection a des options comme<option value="LastName + ' ' + FirstName">Last First</option>
. J'ouvre mes outils de développement, modifie l'value
option d'unealert('PWNED!')
, sélectionne l'option modifiée et envoie le formulaire. Maintenant, chaque fois qu'une autre personne peut voir mon nom d'affichage, ce code s'exécute.eval
est d'exécuter du code qui ne fait pas partie du script que vous avez écrit. Si vous n'avez pas besoin de pouvoir pour le faire (et vous ne le faites presque jamais), évitereval
aide à éviter toute une catégorie de problèmes. C'est une bonne chose si votre code côté serveur n'est pas parfait.Lors du débogage dans Chrome (v28.0.1500.72), j'ai constaté que les variables ne sont pas liées aux fermetures si elles ne sont pas utilisées dans une fonction imbriquée qui produit la fermeture. Je suppose que c'est une optimisation du moteur JavaScript.
MAIS : quand
eval()
est utilisé à l'intérieur d'une fonction qui provoque une fermeture, TOUTES les variables des fonctions externes sont liées à la fermeture, même si elles ne sont pas utilisées du tout. Si quelqu'un a le temps de tester si des fuites de mémoire peuvent en résulter, laissez-moi un commentaire ci-dessous.Voici mon code de test:
Ce que j'aimerais souligner ici, c'est que eval () ne doit pas nécessairement faire référence à la
eval()
fonction native . Tout dépend du nom de la fonction . Ainsi, lors de l'appel du natifeval()
avec un nom d'alias (disonsvar noval = eval;
puis dans une fonction internenoval(expression);
), l'évaluation deexpression
peut échouer lorsqu'elle fait référence à des variables qui devraient faire partie de la fermeture, mais ce n'est pas le cas.la source
Microsoft explique pourquoi eval () est lent dans son navigateur sur le blog IE , Recommandations de performances IE + JavaScript Partie 2: Inefficacité du code JavaScript .
la source
Bottom Line
Si vous avez créé ou aseptisé le code vous
eval
, ce n'est jamais mal .Un peu plus détaillé
eval
est mauvais s'il s'exécute sur le serveur à l'aide d'une entrée soumise par un client qui n'a pas été créée par le développeur ou qui n'a pas été filtrée par le développeur .eval
n'est pas mauvais s'il s'exécute sur le client, même si vous utilisez une entrée non stérilisée conçue par le client .Il est évident que vous devez toujours aseptiser l'entrée, d'avoir un certain contrôle sur ce que votre consume de code.
Raisonnement
Le client peut exécuter n'importe quel code arbitraire qu'il souhaite, même si le développeur ne l'a pas codé; Cela est vrai non seulement pour ce qui est évalué, mais pour l' appel à
eval
lui-même .la source
La seule instance où vous devriez utiliser eval () est lorsque vous devez exécuter JS dynamique à la volée. Je parle de JS que vous téléchargez de manière asynchrone depuis le serveur ...
... Et 9 fois sur 10, vous pourriez facilement éviter de le faire en refactorisant.
la source
eval
est rarement le bon choix. Bien qu'il puisse y avoir de nombreux cas où vous pouvez accomplir ce que vous devez accomplir en concaténant un script ensemble et en l'exécutant à la volée, vous avez généralement des techniques beaucoup plus puissantes et maintenables à votre disposition: notation de tableau associatif (obj["prop"]
est la même queobj.prop
) , fermetures, techniques orientées objet, techniques fonctionnelles - utilisez-les à la place.la source
En ce qui concerne le script client, je pense que la question de la sécurité est un point discutable. Tout ce qui est chargé dans le navigateur est sujet à manipulation et doit être traité comme tel. Il n'y a aucun risque à utiliser une instruction eval () lorsqu'il existe des moyens beaucoup plus faciles d'exécuter du code JavaScript et / ou de manipuler des objets dans le DOM, comme la barre d'URL dans votre navigateur.
Si quelqu'un veut manipuler son DOM, je dis swing. La sécurité pour empêcher tout type d'attaque devrait toujours être la responsabilité de l'application serveur, point final.
D'un point de vue pragmatique, il n'y a aucun avantage à utiliser un eval () dans une situation où les choses peuvent être faites autrement. Cependant, il existe des cas spécifiques où un eval DEVRAIT être utilisé. Dans ce cas, cela peut certainement être fait sans risque de faire exploser la page.
la source
<head></head>
requis, même s'il est vide?Côté serveur, l'eval est utile lorsqu'il s'agit de scripts externes tels que sql ou influxdb ou mongo. Où la validation personnalisée au moment de l'exécution peut être effectuée sans redéployer vos services.
Par exemple un service de réalisation avec les métadonnées suivantes
Qui permettent alors,
Injection directe d'objets / valeurs via une chaîne littérale dans un json, utile pour les modèles de texte
Peut être utilisé comme comparateur, disons que nous établissons des règles pour valider une quête ou des événements dans le CMS
Contre cela:
Peut être des erreurs dans le code et casser des choses dans le service, s'il n'est pas entièrement testé.
Si un pirate peut écrire un script sur votre système, alors vous êtes à peu près foutu.
Une façon de valider votre script est de conserver le hachage de vos scripts dans un endroit sûr, afin que vous puissiez les vérifier avant de l'exécuter.
la source
Je pense que tout cas de valorisation de l'évaluation serait rare. Vous êtes plus susceptible de l'utiliser en pensant qu'il est justifié que vous ne l'utilisez lorsqu'il est réellement justifié.
Les problèmes de sécurité sont les plus connus. Mais sachez également que JavaScript utilise la compilation JIT et cela fonctionne très mal avec eval. Eval est un peu comme une boîte noire pour le compilateur, et JavaScript doit être en mesure de prédire le code à l'avance (dans une certaine mesure) afin d'appliquer en toute sécurité et correctement les optimisations de performances et la portée. Dans certains cas, l'impact sur les performances peut même affecter d'autres codes en dehors d'eval.
Si vous voulez en savoir plus: https://github.com/getify/You-Dont-Know-JS/blob/master/scope%20%26%20closures/ch2.md#eval
la source
Vous pouvez l'utiliser si vous avez un contrôle total sur le code transmis à la
eval
fonction.la source
eval
, la grande question devient alors: quand est-il logique que ce soit une chaîne plutôt qu'un vrai JS?<script async="true" src="...">
. Voir aussi: w3bits.com/async-javascriptUniquement pendant les tests, si possible. Notez également que eval () est beaucoup plus lent que les autres évaluateurs JSON spécialisés, etc.
la source
Il n'y a aucune raison de ne pas utiliser eval () tant que vous pouvez être sûr que la source du code provient de vous ou de l'utilisateur réel. Même s'il peut manipuler ce qui est envoyé dans la fonction eval (), ce n'est pas un problème de sécurité, car il est capable de manipuler le code source du site Web et pourrait donc changer le code JavaScript lui-même.
Alors ... quand ne pas utiliser eval ()? Eval () ne doit pas être utilisé uniquement lorsqu'il existe un risque qu'un tiers le modifie. Comme intercepter la connexion entre le client et votre serveur (mais si c'est un problème, utilisez HTTPS). Vous ne devriez pas utiliser eval () pour analyser du code écrit par d'autres comme dans un forum.
la source
eval
d'une chaîne composée du contenu d'un utilisateur peut permettre à cet utilisateur d'exécuter du code dans le navigateur de l'autre utilisateur.eval
. Cela arrive tout le temps.eval
. Comment est-il utile de blâmer le serveur? Si quelqu'un devait être blâmé, ce devrait être l'attaquant. Indépendamment du blâme, un client qui n'est pas vulnérable à XSS malgré les bogues du serveur est meilleur qu'un client qui est vulnérable, toutes choses étant égales par ailleurs.Si c'est vraiment nécessaire, l'eval n'est pas mal. Mais 99,9% des utilisations d'eval que je rencontre ne sont pas nécessaires (à l'exclusion des éléments setTimeout).
Pour moi, le mal n'est pas une performance ou même un problème de sécurité (enfin, indirectement c'est les deux). Toutes ces utilisations inutiles d'eval s'ajoutent à un enfer de maintenance. Les outils de refactoring sont supprimés. La recherche de code est difficile. Les effets imprévus de ces événements sont légion.
la source
Quand eval () de JavaScript n'est-il pas mal?
J'essaie toujours de me décourager d'utiliser eval . Presque toujours, une solution plus propre et plus facile à entretenir est disponible. Eval n'est pas nécessaire, même pour l'analyse JSON . Eval ajoute à l'enfer de la maintenance . Non sans raison, il est mal vu par des maîtres comme Douglas Crockford.
Mais j'ai trouvé un exemple où il devrait être utilisé:
Lorsque vous devez transmettre l'expression.
Par exemple, j'ai une fonction qui construit un
google.maps.ImageMapType
objet général pour moi, mais je dois lui dire la recette, comment devrait-elle construire l'URL de la tuile à partir des paramètreszoom
etcoord
:la source
tileURL: function (zoom, coord) { return 'http://tile.openstreetmap.org/' + b + '/' + a.x + '/' + a.y + '.png'; },
Mon exemple d'utilisation
eval
: import .Comment cela se fait habituellement.
Mais avec l'aide de
eval
et une petite fonction d'aide, cela devient beaucoup mieux:importable
pourrait ressembler (cette version ne prend pas en charge l'importation de membres concrets).la source
.replace(/name/g, name).replace('path', path)
. Siname
contient la chaîne,"path"
vous pourriez obtenir des surprises.components
est une odeur de code possible; la refactorisation de votre code pourrait éliminer complètement le «problème». Votre solution actuelle n'est que du sucre syntaxique. Si vous insistez pour le faire, alors je recommanderais d'écrire votre propre préprocesseur, à exécuter avant le déploiement. Cela devrait rester à l'eval
écart du code de production.Eval n'est pas mal, juste mal utilisé.
Si vous avez créé le code qui s'y trouve ou pouvez y faire confiance, ça va. Les gens n'arrêtent pas de dire que la saisie des utilisateurs n'a pas d'importance avec eval. Eh bien, en quelque sorte ~
S'il y a une entrée utilisateur qui va au serveur, puis revient au client, et ce code est utilisé dans eval sans être filtré. Félicitations, vous avez ouvert la boîte de Pandore pour que les données des utilisateurs soient envoyées à quiconque.
Selon l'emplacement de l'évaluation, de nombreux sites Web utilisent des SPA, et l'évaluation pourrait faciliter l'accès des utilisateurs aux applications internes, ce qui n'aurait pas été facile autrement. Maintenant, ils peuvent créer une extension de navigateur bidon qui peut enregistrer cette évaluation et voler à nouveau des données.
Je dois juste comprendre quel est l'intérêt de vous en utilisant l'eval. La génération de code n'est pas vraiment idéale quand vous pouvez simplement créer des méthodes pour faire ce genre de choses, utiliser des objets ou similaires.
Maintenant, un bel exemple d'utilisation d'eval. Votre serveur lit le fichier swagger que vous avez créé. De nombreux paramètres d'URL sont créés au format
{myParam}
. Vous souhaitez donc lire les URL, puis les convertir en chaînes de modèle sans avoir à effectuer des remplacements complexes, car vous avez de nombreux points de terminaison. Vous pouvez donc faire quelque chose comme ça. Notez qu'il s'agit d'un exemple très simple.la source
Génération de code. J'ai récemment écrit une bibliothèque appelée Hyperbars qui comble le fossé entre virtual-dom et guidon . Pour ce faire, il analyse un modèle de guidon et le convertit en hyperscript . L'hyperscript est d'abord généré sous forme de chaîne et avant de le renvoyer,
eval()
il le transforme en code exécutable. J'ai trouvéeval()
dans cette situation particulière l'opposé exact du mal.Fondamentalement de
Pour ça
Les performances de
eval()
ne sont pas un problème dans une situation comme celle-ci, car vous n'avez besoin d'interpréter la chaîne générée qu'une seule fois, puis de réutiliser la sortie exécutable plusieurs fois.Vous pouvez voir comment la génération de code a été réalisée si vous êtes curieux ici .
la source
eval
c'est un indice qu'une responsabilité qui appartient au moment de la compilation est passée à l'exécution.Ma conviction est que eval est une fonction très puissante pour les applications Web côté client et sûre ... Aussi sûre que JavaScript, ce qui n'est pas le cas. :-) Les problèmes de sécurité sont essentiellement un problème côté serveur car, maintenant, avec des outils comme Firebug, vous pouvez attaquer n'importe quelle application JavaScript.
la source
eval
doit être sécurisée contre les attaques XSS, ce qui n'est pas toujours facile à bien faire.Eval est utile pour la génération de code lorsque vous n'avez pas de macros.
Par exemple (stupide), si vous écrivez un compilateur Brainfuck , vous voudrez probablement construire une fonction qui exécute la séquence d'instructions sous forme de chaîne, et l'évaluer pour renvoyer une fonction.
la source
eval
.eval
, lorsque l'alternative ( Fonction ) est à la fois plus rapide ( comme expliqué dans MDN ) et plus fiable (empêche les bogues imprévisibles par une meilleure isolation entre le code généré et d'autres codes `` de support '' sur la même page Web).Lorsque vous analysez une structure JSON avec une fonction d'analyse (par exemple, jQuery.parseJSON), elle attend une structure parfaite du fichier JSON (chaque nom de propriété est entre guillemets). Cependant, JavaScript est plus flexible. Par conséquent, vous pouvez utiliser eval () pour l'éviter.
la source
eval
, en particulier. lors de l'obtention de données JSON à partir d'une source tierce. Voir JSON.Stringify sans guillemets sur les propriétés? pour la bonne approche pour analyser "JSON sans noms de clés entre guillemets".string
et définit astring
comme une séquence de zéro ou plusieurs caractères Unicode, entourés de guillemets doubles, en utilisant des échappements antislash.eval
. Dans toute application Web sérieuse multi-locataire, avec des dizaines de développeurs travaillant sur la même base de code, cela est inacceptable.