web-dev-qa-db-fra.com

Quels sont précisément les dangers de l'évaluation (analyse (...))?

Il y a plusieurs questions sur la façon d'éviter d'utiliser eval(parse(...))

Ce qui déclenche les questions:

  • Pourquoi en particulier eval(parse()) devrait-il être évité?
  • Et surtout, quels sont les dangers?
    • Y a-t-il un danger si le code n'est pas utilisé en production? (Je pense, tout danger de récupérer des résultats inattendus. De toute évidence, si vous ne faites pas attention à ce que vous analysez, vous aurez des problèmes. Mais est-ce plus dangereux que d'être bâclé avec get()?)
63
Ricardo Saporta

La plupart des arguments contre eval(parse(...)) surviennent pas en raison de problèmes de sécurité, après tout, aucune affirmation n'est faite sur R comme une interface sûre pour exposer à Internet, mais plutôt parce qu'un tel code fait généralement des choses qui peuvent être accomplies en utilisant des méthodes moins obscures, c'est-à-dire des méthodes qui sont à la fois plus rapides et plus faciles à analyser. Le langage R est censé être de haut niveau, donc la préférence des cognoscenti (et je ne me considère pas dans ce groupe) est de voir un code à la fois compact et expressif.

Le danger est donc que eval(parse(..)) est une méthode détournée pour contourner le manque de connaissances et l'espoir de lever cette barrière est que les gens amélioreront leur utilisation du langage R. La porte reste ouverte mais l'espoir est pour une utilisation plus expressive des autres fonctionnalités. Question de Carl Witthoft plus tôt dans la journée illustré ne sachant pas que la fonction get était disponible, et la question à laquelle il a lié a révélé un manque de compréhension de la façon dont le [[ S'est comporté (et comment $ Était plus limité que [[). Dans les deux cas, une solution eval(parse(..)) pouvait être construite, mais elle était plus maladroite et moins claire que l'alternative.

41
42-

Les problèmes de sécurité ne se posent vraiment que si vous commencez à appeler eval sur des chaînes qu'un autre utilisateur vous a transmises. C'est un gros problème si vous créez une application qui exécute R en arrière-plan, mais pour l'analyse de données où vous écrivez du code à exécuter par vous-même, vous ne devriez pas avoir à vous soucier de l'effet de eval sur la sécurité.

Quelques autres problèmes avec eval(parse( bien que.

Premièrement, le code utilisant eval-parse est généralement beaucoup plus difficile à déboguer que le code non analysé, ce qui est problématique car le logiciel de débogage est deux fois plus difficile que l'écrire en premier lieu.

Voici une fonction avec une erreur.

std <- function()
{
  mean(1to10)
}

Idiot, j'ai oublié l'opérateur du côlon et j'ai mal créé mon vecteur. Si j'essaye de trouver cette fonction, R remarque le problème et lance une erreur, me pointant sur mon erreur.

Voici la version eval-parse.

ep <- function()
{
  eval(parse(text = "mean(1to10)"))
}

Cette source , car l'erreur se trouve dans une chaîne valide. Ce n'est que plus tard, lorsque nous arrivons à exécuter le code que l'erreur est levée. Donc, en utilisant eval-parse, nous avons perdu la capacité de vérification des erreurs à la source.

Je pense également que cette deuxième version de la fonction est beaucoup plus difficile à lire.

L'autre problème avec eval-parse est qu'il est beaucoup plus lent que le code exécuté directement. Comparer

system.time(for(i in seq_len(1e4)) mean(1:10))
   user  system elapsed 
   0.08    0.00    0.07

et

system.time(for(i in seq_len(1e4)) eval(parse(text = "mean(1:10)")))
   user  system elapsed 
   1.54    0.14    1.69
34
Richie Cotton

Habituellement, il existe une meilleure façon de "calculer sur le langage" que de travailler avec des chaînes de code; D'après mon expérience, le code lourd evalparse a besoin de beaucoup de protection pour garantir une sortie sensible.

La même tâche peut généralement être résolue en travaillant directement sur le code R en tant qu'objet langage; Hadley Wickham a un guide utile sur la méta-programmation en R ici :

La fonction defmacro () dans la bibliothèque gtools est mon substitut préféré (pas de jeu de mots R à moitié déterminé) pour la construction evalparse

require(gtools)

# both action_to_take & predicate will be subbed with code

F <- defmacro(predicate, action_to_take, expr = 
    if(predicate) action_to_take)

F(1 != 1, action_to_take = print('arithmetic doesnt work!'))

F(pi > 3, action_to_take = return('good!'))
[1] 'good!'

# the raw code for F
print(F)

function (predicate = stop("predicate not supplied"), action_to_take = stop("action_to_take not supplied")) 
{
    tmp <- substitute(if (predicate) action_to_take)
    eval(tmp, parent.frame())
}
<environment: 0x05ad5d3c> 

L'avantage de cette méthode est que vous êtes assuré de récupérer le code R syntaxiquement légal. Plus d'informations sur cette fonction utile peuvent être trouvées ici :

J'espère que cela pourra aider!

17
RyanGrannell

Dans certains langages de programmation, eval() est une fonction qui évalue une chaîne comme s'il s'agissait d'une expression et renvoie un résultat; dans d'autres, il exécute plusieurs lignes de code comme si elles avaient été incluses au lieu de la ligne incluant l'eval. L'entrée à eval n'est pas nécessairement une chaîne; dans les langages qui prennent en charge les abstractions syntaxiques (comme LISP), l'entrée d'eval consistera en des formes syntaxiques abstraites. http://en.wikipedia.org/wiki/Eval

Il existe toutes sortes d'exploits dont on peut tirer profit si eval n'est pas utilisé correctement.

Un attaquant pourrait fournir un programme avec la chaîne "session.update (authenticated = True)" en tant que données, ce qui mettrait à jour le dictionnaire de session pour définir une clé authentifiée sur True. Pour y remédier, toutes les données qui seront utilisées avec eval doivent être échappées, ou elles doivent être exécutées sans accès à des fonctions potentiellement dangereuses. http://en.wikipedia.org/wiki/Eval

En d'autres termes, le plus grand danger de eval() est le potentiel d'injection de code dans votre application. L'utilisation de eval() peut également entraîner des problèmes de performances dans certaines langues en fonction de ce qui est utilisé.

Plus précisément dans R, c'est probablement parce que vous pouvez utiliser get() à la place de eval(parse()) et vos résultats seront les mêmes sans avoir à recourir à eval()

8
ORION