5

我想编写一个函数,允许用户根据正则表达式匹配数据,但我担心用户字符串的卫生。我知道对于 SQL 查询,您可以使用绑定变量来避免 SQL 注入攻击,但我不确定是否有这样的正则表达式机制。我看到有Regexp.escape,但我想允许有效的正则表达式。

这是示例函数:

  def tagged?(text)
    tags.each do |tag|
      return true if text =~ /#{tag.name}/i
    end
    return false
  end

由于我只是直接匹配,tag.name是否有可能有人可以插入 Proc 调用或其他东西来打破正则表达式并造成破坏?

任何关于最佳实践的建议将不胜感激。

4

2 回答 2

5

Regexp 中的插值字符串不会被执行,但会产生恼人的警告:

/#{exit -3}/.match('test')
# => exits

foo = '#{exit -3}'
/#{foo}/.match('test')
# => warning: regexp has invalid interval
# => warning: regexp has `}' without escape

这两个警告似乎分别与开始 #{ 和结束 } 相关,并且是独立的。

作为一种更有效的策略,您可能希望将标签列表清理为可以运行一次的组合正则表达式。构建和测试 N 个正则表达式的效率通常远低于使用 N 个部分的 1 个正则表达式。

也许是这样的:

class Taggable
  def tags
    @tags
  end

  def tags=(value)
    @tags = value

    @tag_regexp = Regexp.new(
      [
        '^(?:',
        @tags.collect do |tag|
          '(?:' + tag.sub(/\#\{/, '\\#\\{').sub(/([^\\])\}/, '\1\\}') + ')'
        end.join('|'),
        ')$'
      ].to_s,
      Regexp::IGNORECASE
    )
  end

  def tagged?(text)
    !!text.match(@tag_regexp)
  end
end

这可以像这样使用:

e = Taggable.new
e.tags = %w[ #{exit-3} .*\.gif .*\.png .*\.jpe?g ]

puts e.tagged?('foo.gif').inspect

如果执行了退出调用,程序将在那里停止,但它只是将其解释为文字字符串。为了避免警告,它用反斜杠转义。

于 2009-12-31T16:10:40.800 回答
2

您可能应该创建一个Regexp类的实例。

def tagged?(text)
  return tags.any? { |tag| text =~ Regexp.new(tag.name, Regexp::IGNORECASE) }
end
于 2009-12-31T15:34:16.857 回答