Cette fonction est souvent décriée ; un peu pour les traitements supplémentaires causés par l'appel d'un nouvel interpréteur JavaScript, même si c'est relativement négligeable sur des plateformes "normales" ; beaucoup pour les failles de sécurité et d'encapsulation qu'elle permet comme le montre le bout de code ci-dessous :
Code javascript : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | var global = 5; function checkPassword(pass) { // ... // retourne true ou false return false; } function parseScript() { var local = 1; eval('var local = 13;'); eval('var global = 0;'); alert(local); // ==> x = 13 alert(global); // ==> g = 0 !!! eval('window.checkPassword = function(pass) { return true; }'); } parseScript(); var accessOk = checkPassword(''); alert(accessOk); // ==> true !!! |
La fonction eval() utilisée sans précaution peut permettre au script interprété de modifier par inadvertance ou intentionnellement (et dans ce cas de façon malveillante) le code du programme appelant dans la mesure où :
- d'une part elle ne crée pas de nouveau contexte d'exécution mais s'appuie sur le contexte duquel eval() est appelée. Dans l'exemple, la variable local définie dans la fonction appelante parseScript() et celle définie dans eval(), même en utilisant le mot-clé var, désigne en réalité le même objet.
- et d'autre part elle a accès à l'objet global window puisqu'objet global justement ce qui est très compromettant d'un point de vue de la sécurité. Le code du script peut ainsi redéfinir tous les objets et toutes les fonctions du programme appelant comme le montre l'exemple avec la fonction checkPassword().
Pour pallier à la première faille, mais qui n'est pas la plus grave, il est possible d'utiliser le mode strict qui oblige eval() à créer son propre contexte d'exécution. Les variables précédées par le mot-clé var seront bien de nouveaux objets indépendants des objets du contexte appelant, même en cas d'homonymie. La fonction eval() se comporte donc comme une fermeture.
Code javascript : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | var global = 5; function checkPassword(pass) { // ... // retourne true ou false return false; } function parseScript() { 'use strict'; var local = 1; eval('var local = 13;'); eval('var global = 0;'); alert(local); // ==> x = 1 alert(global); // ==> g = 5 eval('window.checkPassword = function(pass) { return true; }'); } parseScript(); var accessOk = checkPassword(''); alert(accessOk); // ==> true !!! |
Cependant persiste le problème de l'accès aux variables globales qui est le vrai point noir de cette fonction. D'où la phrase fameuse de Douglas Crockford à son sujet : "eval is evil".
Il existe heureusement des solutions pour se passer d'eval(), mais ce n'est pas si simple.
Dans une seconde partie, j'expliquerai comment interpréter du JavaScript de façon fiable.