Ruby 在不使用字符串插值的情况下求值字符串

Ruby 在不使用字符串插值的情况下求值字符串,ruby,regex,eval,Ruby,Regex,Eval,AKA如何使用正则表达式查找未转义字符序列 给定的环境设置为: @secret = "OH NO!" $secret = "OH NO!" @@secret = "OH NO!" 从文件中读取的给定字符串如下所示: some_str = '"\"#{:NOT&&:very}\" bad. \u262E\n#@secret \\#$secret \\\\#@@secret"' 我想将其作为Ruby字符串进行计算,但不使用插值。因此,结果应该是: puts safe_eval(s

AKA如何使用正则表达式查找未转义字符序列

给定的环境设置为:

@secret = "OH NO!"
$secret = "OH NO!"
@@secret = "OH NO!"
从文件中读取的给定字符串如下所示:

some_str = '"\"#{:NOT&&:very}\" bad. \u262E\n#@secret \\#$secret \\\\#@@secret"'
我想将其作为Ruby字符串进行计算,但不使用插值。因此,结果应该是:

puts safe_eval(some_str)
#=> "#{:NOT&&:very}" bad. ☮
#=> #@secret #$secret \#@@secret
相比之下,
eval
唯一的解决方案产生

puts eval(some_str)
#=> "very" bad. ☮
#=> OH NO! #$secret \OH NO!

起初我试着:

def safe_eval(str)
  eval str.gsub(/#(?=[{@$])/,'\\#')
end
但这在上述恶意中间案例中失败,产生:

#=> "#{:NOT&&:very}" bad. ☮
#=> #@secret \OH NO! \#@@secret

通过正则表达式,可以确保要转义的字符前有偶数个反斜杠:

def safe_eval(str)
  eval str.gsub( /([^\\](?:\\\\)*)#(?=[{@$])/, '\1\#' )
end
…上面说:

  • 查找不是反斜杠的字符
    [^\\]
  • 后跟两个反斜杠
    (?:\\\\)
    • 重复零次或多次
      *
  • 后跟文字
    #
    字符
  • 并确保在此之后可以看到
    {
    @
    $
    字符
  • 并将其替换为
    • 非反斜杠后面可能跟偶数个反斜杠
    • 然后是反斜杠,然后是
      #

完全不使用eval如何?根据chat中的评论,所需的只是转义引号、换行符和unicode字符。以下是我的解决方案:

ESCAPE_TABLE = {
  /\\n/ => "\n",
  /\\"/ => "\"",
}
def expand_escapes(str)
  str = str.dup
  ESCAPE_TABLE.each {|k, v| str.gsub!(k, v)}
  #Deal with Unicode
  str.gsub!(/\\u([0-9A-Z]{4})/) {|m| [m[2..5].hex].pack("U") }
  str
end
在字符串上调用时,结果是(在变量环境中):


<>虽然我不想特别地对待Unicode,但它是唯一的方法,没有<代码> EVA/COD> > < /P>但是我是否缺少一个运行任意Ruby代码的攻击向量?@ PogRez:如果你在任何地方运行这个服务器,就说你的数据。如果这只是一个本地应用程序,这就足够了。@ Linuxios?说,“听起来你给出了很好的建议,但是你实际上在做的是基于代码< > EVA/COD>的恐惧。你能提供一个不被防范的具体攻击向量吗?”@Phogrez:同意XKCD,让我想一想。是什么阻止人们只使用一些Ruby代码而不是字符串?例如:
some_str='system('rm-rf/'))
?这个问题的动机是一种简单的方法来安全地实现对的答案。FWIW,聊天评论只是一个示例,而不是一个完整的列表。需要支持,例如
\t
\r
\s
等等。但是,这在您的解决方案中显然是可扩展的。虽然不是n个GSUB,而是每个替换一个,我建议使用块形式的单个gsub,它使用查找表来确定替换字符串。@Phrogz:这是个好主意。我稍后再做,我现在有点忙。
"\"\"\#{:NOT&&:very}\" bad. ☮\n\#@secret \\\#$secret \\\\\#@@secret\""