Ruby 在不使用字符串插值的情况下求值字符串
AKA如何使用正则表达式查找未转义字符序列 给定的环境设置为: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
@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
…上面说:
- 查找不是反斜杠的字符
[^\\]
- 后跟两个反斜杠
(?:\\\\)
- 重复零次或多次
*
- 重复零次或多次
- 后跟文字
字符#
- 并确保在此之后可以看到
、{
或@
字符$
- 并将其替换为
- 非反斜杠后面可能跟偶数个反斜杠
- 然后是反斜杠,然后是
#
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\""