web-dev-qa-db-fra.com

Quels sont les problèmes de sécurité avec "eval ()" en JavaScript?

Chaque fois que quelqu'un mentionne eval (), tout le monde dit qu'il y a des "problèmes de sécurité", mais personne n'entre jamais dans les détails de ce qu'ils sont. La plupart des navigateurs modernes semblent être en mesure de déboguer eval () tout aussi bien que le code normal, et les affirmations des gens d'une baisse des performances sont douteuses/dépendent du navigateur.

Quels sont, le cas échéant, les problèmes associés à eval ()? Je n'ai pas pu trouver quoi que ce soit qui pourrait être exploité avec eval () en JavaScript. (Je vois des problèmes avec le code eval () sur le serveur, mais eval () côté client semble être sûr.)

23
Stack Tracer

eval() exécute une chaîne de caractères sous forme de code. Vous utilisez eval() précisément parce que le contenu de la chaîne n'est pas connu à l'avance, ni même généré côté serveur; en gros, vous avez besoin de eval() car le JavaScript lui-même générera la chaîne à partir de données qui ne sont disponibles que dynamiquement, dans le client.

Ainsi, eval() est logique dans les situations où le code JavaScript va générer du code. Ce n'est pas intrinsèquement mauvais , mais c'est difficile à faire en toute sécurité. Les langages de programmation sont conçus pour permettre à un être humain d'écrire des instructions qu'un ordinateur comprend; à cet effet, n'importe quel langage est plein de petites bizarreries et de comportements spéciaux qui sont censés aider le programmeur humain (par exemple l'ajout automatique de ``; '' à la fin de certaines déclarations en JavaScript). Tout cela est agréable et dandy pour une programmation "normale"; mais lorsque vous générez du code à partir d'un autre programme, sur la base de données qui peuvent être potentiellement hostiles (par exemple un extrait de chaîne provenant d'autres utilisateurs du site), vous devez, en tant que développeur du générateur de code, connaître toutes ces bizarreries et empêcher les données hostiles de les exploiter de manière dommageable.

En ce sens, les générateurs de code (et donc eval()) encourent les mêmes problèmes conceptuels que le SQL brut et sa conséquence, attaques par injection SQL . L'assemblage au moment de l'exécution d'une requête SQL à partir de paramètres fournis en externe peut être effectué en toute sécurité, mais cela nécessite de prendre en compte énormément de détails, donc le conseil habituel est de ne pas le faire. Cela se rapporte à l'énigme habituelle de la sécurité, c'est-à-dire qu'elle n'est pas testable: vous pouvez tester si un morceau de code fonctionne correctement sur des données correctes, mais pas qu'il ne fonctionne jamais incorrectement sur des données incorrectes. De même, l'utilisation de eval() en toute sécurité est possible, mais elle est si difficile en pratique qu'elle est déconseillée.

Tout cela est dit en général. Dans votre contexte spécifique, eval() peut être sûr. Cependant, il faut un certain effort pour avoir un contexte sûr pour l'utilisation de eval(), qui a réellement besoin de eval().

30
Thomas Pornin

eval () est un vecteur possible pour les scripts intersites.
Dans des circonstances normales, un attaquant tentant XSS pourrait vouloir obtenir le script <script></script> balise au-delà de l'encodage, des filtres ou des pare-feu éventuellement en place. Si eval () fonctionne sur l'entrée utilisateur, il élimine le besoin de balises de script.

Eval est présent dans de nombreux scripts malveillants car il aide à obscurcir le code et/ou à dissimuler les caractères interdits devant les filtres. Pour cette raison, eval () est souvent vérifié dans les entrées utilisateur. Ainsi, lorsque vous utilisez eval (), vous fournissez potentiellement à l'attaquant l'un de ses outils nécessaires. Je vole une banque et je sais que je n'ai pas besoin de glisser un pistolet devant un détecteur de métal car il y a un tas dans le porte-parapluie à l'intérieur du bâtiment.

14
mcgyver5

Comme expliqué par d'autres, on peut utiliser eval pour créer dynamiquement du code, ce qui rend plus difficile la compréhension du flux de contrôle du programme. Mais, je ne considère pas eval beaucoup plus mal que toutes les autres façons de générer du code au moment de l'exécution, comme document.write(...), object.innerHTML(...) et autres. Bien que ceux-ci soient principalement utilisés pour changer le DOM du programme, ils sont également utilisés pour insérer un nouveau code (c'est-à-dire ajouter une instruction de script au code ou un nouvel élément avec un gestionnaire onXXXX, etc.).

Et même si eval est souvent utilisé dans les attaques (XSS, malvertisement ...) pour contourner les filtres ou masquer le véritable objectif du code, il est souvent utilisé sous une forme obscurcie, c'est-à-dire un code comme z='ev'; z+='al'; v=window; v[z]("alert(1)"). Cela signifie que vous n'êtes pas du bon côté si vous essayez simplement de filtrer le code avec des appels explicites d'eval, car soit l'appel est obscurci, soit de "bonnes" fonctions comme innerHTML sont utilisées à des fins inappropriées.

4
Steffen Ullrich

En plus des excellents points soulevés ici, je voudrais clarifier: ce que vous traitez essentiellement chaque fois que vous utilisez eval () doit répondre aux questions suivantes:

  • Vaut-il la peine d'être sécurisé?
  • Dans quelle mesure puis-je le sécuriser et ce niveau est-il acceptable?
  • Dans quelle mesure puis-je être sûr qu'il restera sécurisé au cours des futures évolutions de l'équipe de base de code et de développement?
  • Comment le risque et la quantité d'efforts requis par ce qui précède se comparent-ils à l'effort de construction du code de telle manière que l'exécution de code généré dynamiquement et éventuellement inconnu n'est pas nécessaire?

Si vous avez réfléchi à ces questions plus complètement que ne le ferait un attaquant et envisagez toujours d'utiliser eval (), allez-y. Vous pourriez vous sentir fatigué de penser cela au cours de votre carrière de développement et commencer à éviter son utilisation simplement par principe.

2
S.C.