eval(解析(...))的危险是什么?

时间:2012-11-30 17:20:06

标签: r parsing eval

关于如何避免使用eval(parse(...))

,有几个问题

这引发了一些问题:

  • 为什么要特别要避免eval(parse())
  • 最重要的是,危险是什么?
    • 如果代码未在生产中使用,是否存在危险? (我在想,有可能收回意想不到的结果。很明显,如果你不小心你正在解析什么,你就会遇到问题。但这比get()草率更危险吗?)

4 个答案:

答案 0 :(得分:39)

由于安全问题,针对eval(parse(...))的大多数论据都出现而不是,毕竟,没有人声称R是一个暴露于互联网的安全接口,而是因为这样代码通常是使用不那么模糊的方法来完成的事情,即既快又更人性化的方法。 R语言应该是高级的,因此认知的偏好(我不认为自己在该组中)是看到既紧凑又富有表现力的代码。

所以危险在于eval(parse(..))是一种绕过缺乏知识的后门方法,而提出这种障碍的希望是人们会改善他们对R语言的使用。门仍然打开,但希望更有表现力地使用其他功能。 Carl Witthoft's question earlier today说明不知道get函数可用,并且question he linked to表示对[[函数的行为方式缺乏了解(以及$如何比[[更有限。在这两种情况下都可以构建一个eval(parse(..))解决方案,但它比其他方案更笨拙,更不清晰。

答案 1 :(得分:34)

如果您开始在另一个用户传递给您的字符串上调用eval,则只会出现安全问题。如果您正在创建在后台运行R的应用程序,这是一个大问题,但对于您编写要由您自己运行的代码的数据分析,您不必担心eval的影响关于安全。

eval(parse(的其他一些问题。

首先,使用eval-parse的代码通常比非分析代码更难调试,这是有问题的,因为调试软件首先是twice as difficult编写它。

这是一个错误的函数。

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

愚蠢的我,我已经忘记了冒号操作员并错误地创建了我的矢量。如果我尝试使用此函数,那么R会注意到问题并抛出错误,指出我的错误。

这是eval-parse版本。

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

来源,因为错误位于有效字符串中。只是稍后,当我们运行代码时才会抛出错误。因此,通过使用eval-parse,我们已经失去了源时错误检查功能。

我还认为这个函数的第二个版本更难阅读。

eval-parse的另一个问题是它比直接执行的代码慢得多。比较

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

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

答案 2 :(得分:17)

通常有一种比使用代码字符串更好的“计算语言”的方法;根据我的经验,evalparse重码需要很多安全防护来保证合理的输出。

通常可以通过直接将R代码作为语言对象来解决相同的任务; Hadley Wickham在R here中有一个关于元编程的有用指南:

gtools库中的defmacro()函数是我最喜欢的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> 

此方法的好处是可以保证您可以获得语法上合法的R代码。有关此有用功能的更多信息,请参见here

希望有所帮助!

答案 3 :(得分:8)

  

在某些编程语言中,eval()是一个评估函数   一个字符串,好像它是一个表达式并返回一个结果;在   其他人,它执行多行代码,就像它们一样   包括而不是包括eval的行。 eval的输入是   不一定是一串;在支持句法的语言中   抽象(如Lisp),eval的输入将包含抽象   句法形式。   http://en.wikipedia.org/wiki/Eval

如果eval使用不当,可以利用各种漏洞利用。

  

攻击者可以提供带有字符串的程序   “session.update(authenticated = True)”作为数据,将更新   会话字典将经过身份验证的密钥设置为True。要补救   这样,所有将与eval一起使用的数据必须被转义,或者它   必须运行而无法访问可能有害的功能。   http://en.wikipedia.org/wiki/Eval

换句话说,eval()的最大危险是代码注入应用程序的可能性。使用eval()也会导致某些语言出现性能问题,具体取决于所使用的内容。

特别是在R中,可能是因为您可以使用get()代替eval(parse())而且您的结果将是相同的,而不必诉诸eval()