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

Ric*_*rta 62 parsing eval r

关于如何避免使用有几个问题 eval(parse(...))

这引发了一些问题:

  • 为什么要特别eval(parse())避免?
  • 最重要的是,危险是什么?
    • 如果代码没有用于生产,是否有任何危险?(我在想,任何可能会产生意想不到的结果的危险.很明显,如果你不小心你正在解析什么,你就会遇到问题.但这是否比邋with更危险get()?)

42-*_*42- 41

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

所以危险在于这eval(parse(..))是一种绕过缺乏知识的后门方法,并且提出这个障碍的希望是人们将改善他们对R语言的使用.门仍然打开,但希望更有表现力地使用其他功能.Carl Witthoft今天早些时候提出的问题说明并不知道该get功能是否可用,而且他所关联问题暴露了对[[功能如何表现缺乏理解(以及如何$更有限[[).在这两种情况下eval(parse(..))都可以构建一个解决方案,但它比其他方案更笨拙,更不清晰.


Ric*_*ton 34

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

eval(parse(但是还有其他一些问题.

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

这是一个错误的函数.

std <- function()
{
  mean(1to10)
}
Run Code Online (Sandbox Code Playgroud)

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

这是eval-parse版本.

ep <- function()
{
  eval(parse(text = "mean(1to10)"))
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

system.time(for(i in seq_len(1e4)) mean(1:10))
   user  system elapsed 
   0.08    0.00    0.07
Run Code Online (Sandbox Code Playgroud)

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


Rya*_*ell 17

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

通常可以通过直接将R代码作为语言对象来解决相同的任务; 哈德利韦翰对R中的元编程了有益的指导在这里:

对于evalparse构造,gtools库中的defmacro()函数是我最喜欢的替代品(没有半开的R pun意图)

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> 
Run Code Online (Sandbox Code Playgroud)

这种方法的好处是你可以保证恢复语法上合法的R代码.有关此有用功能的更多信息,请访问:

希望有所帮助!

  • 惊人!感谢您指出gtools和defmacro (2认同)

ORI*_*ION 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()

  • RAppArmor包中有一个安全版本的`eval`(`eval.secure`),它在沙箱中执行,除非父进程具有超级用户权限,否则不能执行超级用户权限. (15认同)
  • 字符串a*smart*用户或黑客可以使用的具体示例:`T < - FALSE; F < - TRUE`,`rm(list = ls())`,`system("rm -rf your_directories")`,`source("http://.../virus.R")`. (10认同)