63 votes

Quels sont précisément les dangers de eval(parse(...)) ?

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

Ce qui suscite des questions :

  • Pourquoi spécifiquement eval(parse()) être évitée ?
  • Et surtout, quels sont les dangers ?
    • Y a-t-il des dangers si le code n'est pas utilisé en production ? (Je pense, tout danger de retour de résultats non intentionnels. Il est clair que si vous ne faites pas attention à ce que vous analysez, vous aurez des problèmes. Mais est-ce plus dangereux que d'être négligent dans l'utilisation de get() ?)

41voto

BondedDust Points 105234

La plupart des arguments contre eval(parse(...)) surgir pas pour des raisons de sécurité, après tout, rien ne dit que R est une interface sûre à exposer à l'Internet, mais plutôt parce que ce 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 par l'homme. Le langage R est censé être de haut niveau, aussi la préférence des connaisseurs (et je ne me considère pas dans ce groupe) est de voir un code à la fois compact et expressif.

Donc le danger est que eval(parse(..)) est une méthode détournée pour contourner le manque de connaissances et l'espoir, en levant cette barrière, est que les gens améliorent leur utilisation du langage R. La porte reste ouverte, mais on espère une utilisation plus expressive des autres fonctionnalités. La question posée par Carl Witthoft plus tôt aujourd'hui illustré sans savoir que le get était disponible, et la fonction question qu'il a liée à a révélé un manque de compréhension de la façon dont le [[ s'est comportée (et comment $ était plus limitée que [[ ). Dans les deux cas, un eval(parse(..)) Une solution a pu être construite, mais elle était plus compliquée et moins claire que l'alternative.

34voto

Richie Cotton Points 35365

Les problèmes de sécurité ne se posent réellement que si vous commencez à appeler eval sur des chaînes de caractères qu'un autre utilisateur vous a transmises. Il s'agit d'un problème important 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 la fonction eval sur la sécurité.

D'autres problèmes avec eval(parse( cependant.

Tout d'abord, 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 les logiciels de débogage sont deux fois plus difficile que de l'écrire en premier lieu.

Voici une fonction qui contient une erreur.

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

Je suis stupide, j'ai oublié l'opérateur deux-points et j'ai créé mon vecteur de façon erronée. Si j'essaie de créer cette fonction, R remarque le problème et affiche une erreur, me montrant du doigt mon erreur.

Voici la version eval-parse.

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

Ce site sera car l'erreur se trouve dans une chaîne de caractères valide. Ce n'est que plus tard, lorsque nous exécutons le code, que l'erreur est levée. Ainsi, en utilisant eval-parse, nous avons perdu la possibilité de vérifier les 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 directement exécuté. Comparez

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

17voto

RyanGrannell Points 821

En général, il y a une meilleure façon de "calculer sur le langage" que de travailler avec des chaînes de code ; le code lourd d'evalparse a besoin de beaucoup de protections pour garantir un résultat raisonnable, d'après mon expérience.

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

La fonction defmacro() de la bibliothèque gtools est mon substitut préféré (sans mauvais jeu de mots) de 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 avez la garantie d'obtenir un code R conforme à la syntaxe. Pour en savoir plus sur cette fonction utile, consultez ici :

J'espère que cela vous aidera !

8voto

jcalabris Points 987

Dans certains langages de programmation, eval() est une fonction qui évalue une chaîne de caractères comme s'il s'agissait d'une expression et renvoie un résultat. d'autres, elle exécute plusieurs lignes de code comme si elles avaient été incluses au lieu de la ligne incluant l'évaluation. L'entrée de eval n'est n'est pas nécessairement une chaîne de caractères. syntaxiques (comme Lisp), l'entrée de eval sera constituée de formes syntaxiques formes syntaxiques abstraites. http://en.wikipedia.org/wiki/Eval

Il existe toutes sortes d'exploits dont on peut tirer parti si eval est mal utilisé.

Un attaquant peut fournir un programme avec la chaîne de caractères "session.update(authenticated=True)" en tant que données, ce qui mettrait à jour le dictionnaire de session pour définir une clé authentifiée comme étant True. Pour remédier à Pour remédier à cela, toutes les données utilisées avec eval doivent être échappées ou doit être exécutée sans accès aux 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 causer des problèmes de performance dans certaines langues, selon l'usage qui en est fait.

Spécifiquement en R, c'est probablement parce que vous pouvez utiliser get() à la place de eval(parse()) et vous obtiendrez les mêmes résultats sans avoir à recourir au eval()

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X