La plupart des langues modernes (qui sont en quelque sorte interprétées) ont une sorte de fonction d' évaluation . Une telle fonction exécute un code de langue arbitraire, la plupart du temps passée comme argument principal sous forme de chaîne (différentes langues peuvent ajouter plus de fonctionnalités à la fonction eval).
Je comprends que les utilisateurs ne devraient pas être autorisés à exécuter cette fonction ( modifier, c'est-à-dire prendre directement ou indirectement une entrée arbitraire d'un utilisateur arbitraire à transférer eval
), en particulier avec un logiciel côté serveur, car ils pourraient forcer le processus à exécuter du code malveillant. De cette manière, les tutoriels et les communautés nous disent de ne pas utiliser eval. Cependant, eval est souvent utile et utilisé:
- Règles d'accès personnalisées aux éléments logiciels (IIRC OpenERP dispose d'un objet
ir.rule
pouvant utiliser du code python dynamique). - Calculs et / ou critères personnalisés (OpenERP a des champs comme celui-ci pour permettre des calculs de code personnalisés).
- Analyseurs de rapport OpenERP (oui, je sais que je vous fais peur avec OpenERP, mais c’est le principal exemple que j’ai).
- Coder les effets des sorts dans certains jeux de rôle.
Ils sont donc utiles, dans la mesure où ils sont utilisés correctement. L'avantage principal est que cette fonctionnalité permet aux administrateurs d'écrire du code personnalisé sans avoir à créer davantage de fichiers et à les inclure (bien que la plupart des frameworks utilisant des fonctionnalités eval disposent également d'un moyen de spécifier un fichier, un module, un package, ... à lire).
Cependant, eval est un mal dans la culture populaire. On pense à des choses comme une intrusion dans votre système.
Cependant, il existe d'autres fonctions qui pourraient être néfastes si les utilisateurs y avaient accès: déconnexion, lecture, écriture (sémantique de fichier), allocation de mémoire et arithmétique de pointeur, accès au modèle de base de données (même sans prendre en compte les cas injectables en SQL).
Donc, en gros, la plupart du temps quand tout code est pas écrit correctement ou non surveillé correctement (ressources, les utilisateurs, les environnements, ...), le code est mal et peut même conduire à l' impact économique.
Mais il y a quelque chose de spécial avec les eval
fonctions (quelle que soit la langue).
Question : Existe-t-il un fait historique pour que cette peur fasse partie de la culture populaire, au lieu d’accorder la même attention à d’autres caractéristiques potentiellement dangereuses?
la source
eval
, il dispose d'une fonction interne appeléesafe_eval
qui prépare l'environnement à empêcher le code de faire des choses dangereuses. Des bogues ont été trouvés, cependant, car Python est un langage assez flexible, et donc difficile à contrôler.Réponses:
Une
eval
fonction en elle-même n'est pas mauvaise, et il y a un point subtil que je ne crois pas que vous faites valoir:Autoriser un programme à exécuter des entrées utilisateur arbitraires est mauvais
J'ai écrit un code qui utilisait un
eval
type de fonction et qui était sécurisé: le programme et les paramètres étaient codés en dur. Parfois, il n’existe aucune fonctionnalité de langue ou de bibliothèque permettant de répondre aux besoins du programme; l’exécution d’une commande shell est le chemin court. "Je dois finir de coder cela en quelques heures, mais écrire de Java / .NET / PHP / n'importe quel code prendra deux jours. Ou je peux leeval
faire en cinq minutes."Une fois que vous autorisez les utilisateurs à exécuter tout ce qu'ils veulent, même s'ils sont verrouillés par des privilèges utilisateur ou derrière un écran "sécurisé", vous créez des vecteurs d'attaque. Chaque semaine, un CMS, un logiciel de blogging, etc. au hasard comporte une faille de sécurité qui permet à un attaquant d'exploiter une telle faille. Vous comptez sur la totalité de la pile de logiciels pour protéger l'accès à une fonction pouvant être utilisée
rm -rf /
ou à une autre tâche catastrophique (remarque: cette commande a peu de chances de réussir, mais elle échouera après avoir causé un petit dommage).Oui, il y a un précédent historique. En raison des nombreux bogues corrigés au fil des ans dans divers logiciels permettant à des attaquants distants d’exécuter du code arbitraire, l’idée de l’opération
eval
est tombée en désuétude. Les langages et les bibliothèques modernes possèdent de nombreuses fonctionnalités qui la rendenteval
moins importante, et ce n’est pas un hasard. Cela rend les fonctions plus faciles à utiliser et réduit le risque d’exploitation.Une grande attention a été portée à de nombreuses fonctionnalités potentiellement peu sûres dans les langages populaires. La question de savoir si une personne reçoit plus d’attention est avant tout une question d’opinion, mais les
eval
fonctionnalités présentent certainement un problème de sécurité prouvable et facile à comprendre. D'une part, ils permettent d'exécuter des commandes du système d'exploitation, notamment les commandes intégrées au shell et les programmes externes standard (par exemplerm
oudel
). Deux, combiné à d’autres exploits, un attaquant peut télécharger son propre script exécutable ou shell, puis l’exécuter via votre logiciel, ouvrant ainsi la porte à presque tout ce qui se passe (rien de bon).C'est un problème difficile. Le logiciel est complexe et une pile de logiciels (par exemple, LAMP ) est constituée de plusieurs logiciels interagissant de manière complexe. Faites attention à la manière dont vous utilisez les fonctionnalités de langage telles que celle-ci et n'autorisez jamais les utilisateurs à exécuter des commandes arbitraires.
la source
eval
peut élever des privilèges. ce qui n'est pas un problème s'ils sont déjà élevés.rm -rf /
, il n’est pas nécessaire de le faire de manière compliquée via un IDE. Le problème,eval
c'est que cela ouvre cette capacité à beaucoup d'acteurs qui ne devraient pas en avoir.Une partie de cela est simplement que la nuance est difficile. Il est facile de dire que ne jamais utiliser goto, des champs publics, une interpolation de chaîne pour des requêtes SQL ou eval. Ces déclarations ne doivent pas être comprises comme indiquant qu'il n'y a jamais, en aucune circonstance, de raison de les utiliser. Mais les éviter en règle générale est une bonne idée.
Eval est fortement découragé car il combine plusieurs problèmes communs.
Premièrement, il est sujet aux attaques par injection. Ici, c'est comme l'injection SQL en ce que lorsque des données contrôlées par l'utilisateur sont insérées dans le code, il est facile de permettre accidentellement l'insertion de code arbitraire.
Deuxièmement, les débutants ont tendance à utiliser eval pour contourner un code mal structuré. Un codeur débutant pourrait écrire un code qui ressemble à:
Cela fonctionne, mais c'est vraiment la mauvaise façon de résoudre ce problème. Évidemment, utiliser une liste serait bien mieux.
Troisièmement, eval est généralement inefficace. Beaucoup d’efforts sont consacrés à l’accélération de la mise en œuvre de notre langage de programmation. Mais eval est difficile à accélérer et son utilisation aura généralement des effets néfastes sur vos performances.
Donc, eval n'est pas mauvais. Nous pourrions dire que eval est diabolique, car bon, c’est une façon accrocheuse de le dire. Tout codeur débutant doit absolument rester à l’écart de eval car, quoi qu’ils veuillent faire, eval est presque certainement la mauvaise solution. Pour certains cas d'utilisation avancés, eval a du sens, et vous devriez l'utiliser, mais évidemment, faites attention aux pièges.
la source
var x = 3; print(x)
est compilé, il n'est pas nécessaire que le code source sache que la source a utilisé le nom "x". Pourvar x = 3; print(eval("x"))
pouvoir fonctionner, ce mappage doit être enregistré. C'est un problème réel: dans Common Lisp(let ((x 3)) (print (eval 'x)))
, une exception de variable non liée sera levée, car la variable lexicale x n'a aucun lien avec le nom une fois le code compilé.Cela revient à dire que "l'exécution de code arbitraire" est tech-talk pour "capable de faire n'importe quoi". Si quelqu'un est capable d'exploiter l'exécution de code arbitraire dans votre code, il s'agit littéralement de la pire vulnérabilité de sécurité possible, car cela signifie qu'il est capable de faire tout ce que votre système peut faire.
Les "autres bogues potentiellement dangereux" peuvent avoir des limites, ce qui signifie qu'ils sont, par définition, moins dommageables qu'une exécution de code arbitraire exploitée.
la source
eval
n'est le cas.Il y a une raison pratique et une raison théorique.
La raison pratique est que nous observons que cela pose souvent des problèmes. Il est rare que eval aboutisse à une bonne solution et aboutit souvent à une mauvaise solution: vous en auriez une meilleure si vous aviez prétendu que eval n'existait pas et que vous abordiez le problème différemment. Donc, le conseil simplifié consiste à l'ignorer, et si vous proposez un cas dans lequel vous souhaitez ignorer le conseil simplifié, eh bien, espérons que vous y avez suffisamment réfléchi pour comprendre pourquoi le conseil simplifié ne s'applique pas et le point commun. les pièges ne vous toucheront pas.
La raison plus théorique est que s'il est difficile d'écrire un bon code, il est encore plus difficile d'écrire du code qui écrit un bon code. Que vous utilisiez eval ou générez des instructions SQL en collant des chaînes ou en écrivant un compilateur JIT, ce que vous tentez est souvent plus difficile que prévu. Le potentiel d’injection de code malveillant est une partie importante du problème, mais mis à part cela, il est généralement plus difficile de connaître le code correct si votre code n’existe même pas avant l’exécution. Le conseil simplifié est donc de vous simplifier la vie: "utiliser des requêtes SQL paramétrées", "ne pas utiliser eval".
Exemple: utilisez un compilateur ou un interprète Lua (ou autre) dans votre jeu pour permettre aux concepteurs de jeux de disposer d’un langage plus simple que C ++ (ou autre) pour décrire les effets de sorts. La plupart des "problèmes d'eval" ne s'appliquent pas si vous ne faites qu'évaluer un code qui a été écrit, testé et inclus dans le jeu, dans le DLC ou ce que vous avez. C'est juste mélanger les langues. Les gros problèmes que vous rencontrez lorsque vous essayez de générer Lua (ou C ++, SQL, ou des commandes de shell, etc.) à la volée, et de le gâcher.
la source
Non, il n'y a pas de fait historique évident.
Les maux d’éval sont évidents depuis le début. D'autres caractéristiques sont légèrement dangereuses. Les gens peuvent supprimer des données. Les gens peuvent voir des données qu'ils ne devraient pas. Les gens peuvent écrire des données qu'ils ne devraient pas. Et ils ne peuvent faire la plupart de ces choses que si vous vous trompez et ne validez pas les entrées de l'utilisateur.
Avec eval, ils peuvent pirater le pentagone et lui donner l’impression de le faire. Ils peuvent inspecter vos frappes au clavier pour obtenir vos mots de passe. En supposant un langage complet de Turing, ils peuvent littéralement faire tout ce que votre ordinateur est capable de faire.
Et vous ne pouvez pas valider l'entrée. C'est une chaîne de forme libre arbitraire. Le seul moyen de le valider serait de construire un analyseur et un moteur d'analyse de code pour le langage en question. Bonne chance avec ça.
la source
Je pense que cela se résume aux aspects suivants:
Nécessité
Ce que j'essaie de dire est: vous avez besoin de lire / écrire pour presque les outils de base. Même chose pour stocker les meilleurs scores de votre jeu si génial.
Sans lecture / écriture, votre éditeur d'image est inutile. Sans
eval
? Je vais vous écrire un plugin personnalisé pour ça!Utilisation (surveillée)
De nombreuses méthodes peuvent être potentiellement dangereuses. Comme par exemple le
read
etwrite
. Un exemple courant est un service Web vous permettant de lire des images d’un répertoire spécifique en spécifiant le nom. Cependant, le "nom" peut en fait être n'importe quel chemin d'accès (relatif) valide sur le système, ce qui vous permet de lire tous les fichiers auxquels le service Web a accès, pas seulement les images. Abuser de cet exemple simple est appelé "parcours transversal". Si votre application autorise la traversée de chemins, c'est mauvais. Unread
sans se défendre contre la traversée d'un chemin peut être appelé le mal.Cependant, dans d'autres cas, la chaîne for
read
est entièrement sous le contrôle des programmeurs (peut-être codée en dur?). Dans ce cas, ce n’est guère mal à utiliserread
.Accès
Maintenant, un autre exemple simple, en utilisant
eval
.Quelque part dans votre application Web, vous voulez du contenu dynamique. Vous allez permettre aux administrateurs de saisir un code exécutable. Étant donné que les administrateurs sont des utilisateurs de confiance, cela peut théoriquement être correct. Assurez-vous simplement de ne pas exécuter le code soumis par des non-administrateurs, et tout va bien.
(C'est-à-dire, jusqu'à ce que vous ayez renvoyé ce sympathique administrateur mais que vous ayez oublié de révoquer son accès. Maintenant, votre application web est mise à la corbeille).
Vérifiabilité.
Je pense qu'un autre aspect important est la facilité de vérification des entrées de l'utilisateur.
Vous utilisez une entrée utilisateur dans un appel en lecture? Assurez-vous simplement (très) que l'entrée pour l'appel de lecture ne contient rien de malveillant. Normalisez le chemin et vérifiez que le fichier ouvert se trouve dans votre répertoire de supports. Maintenant c'est sûr.
Entrée de l'utilisateur lors d'un appel en écriture? Même!
Injection SQL? Échappez-vous-en ou utilisez des requêtes paramétrées et vous êtes en sécurité.
Eval? Comment allez-vous vérifier l'entrée utilisée pour l'
eval
appel? Vous pouvez travailler très fort, mais c'est vraiment très difficile (voire impossible) de le faire fonctionner en toute sécurité.Attaques en plusieurs étapes
Maintenant, chaque fois que vous utilisez une entrée utilisateur, vous devez peser les avantages de son utilisation par rapport aux dangers. Protégez son utilisation autant que vous le pouvez.
Considérons à nouveau les
eval
éléments capables dans l'exemple d'administration. Je vous ai dit que c'était en quelque sorte ok.Maintenant, considérez qu'il y a effectivement un endroit dans votre application web où vous avez oublié d'échapper au contenu utilisateur (HTML, XSS). C'est une infraction moins grave qu'une évaluation accessible à l'utilisateur. Mais, en utilisant le contenu d'utilisateur non échappé, un utilisateur peut prendre en charge le navigateur Web d'un administrateur et ajouter un
eval
blob actif dans la session des administrateurs, permettant ainsi à nouveau un accès complet au système.(La même attaque en plusieurs étapes peut être effectuée avec une injection SQL à la place de XSS, ou des écritures de fichiers arbitraires remplaçant le code exécutable au lieu de les utiliser
eval
)la source
eval("hard coded string" + user_input_which_should_be_alphanumeric + "remainder")
. Il est possible de vérifier que l'entrée est alphanumérique. De plus, "Est-ce que ça s'arrête" est orthogonal à "Est-ce qu'il modifie / n'accède pas à l'état qu'il ne devrait pas toucher" et "Est-ce que cela appelle des méthodes qu'il ne devrait pas appeler".Pour que cette fonctionnalité fonctionne, cela signifie que je dois conserver une couche de réflexion permettant un accès complet à l'état interne du programme.
Pour les langages interprétés, je peux simplement utiliser l'état interpréteur, ce qui est facile, mais combiné aux compilateurs JIT, il augmente encore considérablement la complexité.
Sans cela
eval
, le compilateur JIT peut souvent prouver que les données locales d'un thread ne sont pas accessibles à partir d'un autre code. Il est donc parfaitement acceptable de réorganiser les accès, d'omettre les verrous et de mettre en cache les données souvent utilisées plus longtemps. Lorsqu'un autre thread exécute uneeval
instruction, il peut s'avérer nécessaire de synchroniser le code compilé JIT en cours d'exécution avec celui-ci. Par conséquent, le code généré par JIT a besoin d'un mécanisme de secours qui retourne à une exécution non optimisée dans un laps de temps raisonnable.Ce type de code a tendance à avoir beaucoup de bugs subtils, difficiles à reproduire, et en même temps, il limite également l'optimisation dans le compilateur JIT.
Pour les langages compilés, le compromis est encore pire: la plupart des optimisations sont interdites et je dois conserver des informations sur les symboles et un interprète, de sorte que la flexibilité supplémentaire ne vaut généralement pas la peine - il est souvent plus facile de définir une interface avec certains serveurs internes. structures, par exemple en donnant à la vue de script et au contrôleur un accès simultané au modèle du programme .
la source
Je rejette la prémisse qui
eval
est considérée comme plus diabolique que l'arithmétique de pointeur ou plus dangereuse que l'accès direct à la mémoire et au système de fichiers. Je ne connais aucun développeur avisé qui pourrait croire cela. De plus, les langages prenant en charge l’arithmétique de pointeur / l’accès direct à la mémoire ne prennent généralement pas en charge,eval
et inversement, je tiens donc à préciser à quelle fréquence une telle comparaison serait même pertinente.Mais
eval
peut-être une vulnérabilité plus connue , pour la simple raison qu’elle est supportée par JavaScript. JavaScript est un langage en mode bac à sable sans accès direct à la mémoire ou au système de fichiers. Par conséquent, il ne dispose tout simplement pas de ces vulnérabilités, ce qui limite les faiblesses de la mise en œuvre du langage lui-même.Eval
est donc l’une des caractéristiques les plus dangereuses du langage, car elle ouvre la possibilité d’une exécution arbitraire du code. Je crois que beaucoup plus de développeurs développent en JavaScript qu'en C / C ++, ileval
est donc tout simplement plus important de savoir que les débordements de mémoire tampon pour la majorité des développeurs.la source
Aucun programmeur sérieux ne considérerait Eval comme "mal". C'est simplement un outil de programmation, comme un autre. La crainte (s'il y a une crainte) de cette fonction n'a rien à voir avec la culture populaire. Il s'agit simplement d'une commande dangereuse, souvent mal utilisée, qui peut créer de graves failles de sécurité et dégrader les performances. D'après ma propre expérience, je dirais qu'il est rare de rencontrer un problème de programmation qui ne puisse être résolu de manière plus sûre et efficace par d'autres moyens. Les programmeurs les plus susceptibles d'utiliser eval sont ceux qui sont probablement les moins qualifiés pour le faire en toute sécurité.
Cela dit, il existe des langues où l’utilisation d’eval est appropriée. Perl vient à l'esprit. Cependant, je trouve personnellement que c'est très rarement nécessaire dans d'autres langues plus modernes, qui prennent en charge de manière native la gestion structurée des exceptions.
la source
Je pense que vous couvrez assez bien la partie suivante de votre question (c'est moi qui souligne):
Pour les 95% qui l'utilisent correctement, c'est très bien; mais il y aura toujours des gens qui ne l'utilisent pas correctement. Certains d’entre eux devront faire preuve d’inexpérience et de capacités, le reste sera malicieux.
Il y aura toujours des gens qui veulent repousser les limites et trouver des failles de sécurité, certaines pour le bien, d'autres pour le mal.
En ce qui concerne les faits historiques,
eval
les fonctions de type permettent essentiellement l’ exécution de code arbitraire qui était auparavant exploité dans le populaire CMS Web, Joomla! . Avec Joomla! alimentant plus de 2,5 millions de sites dans le monde , cela représente un dommage potentiel non seulement pour les visiteurs de ces sites, mais aussi pour l'infrastructure hébergée et la réputation des sites / entreprises exploités.Le Joomla! Cet exemple peut être simple, mais c’est un enregistrement.
la source
Il y a de bonnes raisons de décourager l'utilisation de
eval
(bien que certaines soient spécifiques à certaines langues).eval
est souvent surprenant (c’est-à-dire que vouseval(something here)
devriez faire une chose mais en faire une autre, en déclenchant éventuellement des exceptions)Personnellement, je n'irais pas jusqu'à dire que c'est mal, mais je contesterai toujours l'utilisation d'
eval
une révision de code, avec le libellé du type "avez-vous envisagé un code ici ?" (si j’ai le temps de faire au moins un remplacement provisoire) ou "êtes-vous sûr qu’une évaluation est vraiment la meilleure solution ici?" (si je ne le fais pas)la source
Dans Society of Mind , chapitre 6.4, de Minsky , il déclare
Lorsqu'un programme (B) écrit un autre programme (A), il fonctionne comme un méta-programme. Le sujet de B est le programme A.
Il y a un programme en C. C'est celui dans votre tête qui écrit le programme B.
Le danger est qu'il peut y avoir quelqu'un (C ') avec une intention malveillante, qui peut interférer dans ce processus, de sorte que vous obtenez des choses comme l'injection de SQL.
Le défi consiste à rendre les logiciels plus intelligents sans les rendre également plus dangereux.
la source
Vous avez beaucoup de bonnes réponses ici et la raison principale est clairement que l'exécution de code arbitraire est mauvaise, mais j'ajouterai un autre facteur que d'autres n'ont abordé que de façon marginale:
Il est très difficile de dépanner le code en cours d’évaluation à partir d’une chaîne de texte. Vos outils de débogage normaux sortent presque de la fenêtre et vous êtes réduit au traçage ou à l'écho très traditionnel. Évidemment, cela n'a pas tellement d'importance si vous avez un fragment dans une ligne que vous voulez,
eval
mais en tant que programmeur expérimenté, vous pouvez probablement trouver une meilleure solution pour cela, alors que la génération de code à grande échelle peut être quelque part qu'une fonction d'évaluation devient un allié potentiellement utile.la source