RoR 4中带有验证的正则表达式


83

有以下代码:

class Product < ActiveRecord::Base
  validates :title, :description, :image_url, presence: true
  validates :price, numericality: {greater_than_or_equal_to: 0.01}
  validates :title, uniqueness: true
  validates :image_url, allow_blank: true, format: {
      with: %r{\.(gif|jpg|png)$}i,
      message: 'URL must point to GIT/JPG/PNG pictures'
  }
end

它可以工作,但是当我尝试使用“ rake test”对其进行测试时,我会捕获以下消息:

rake aborted!
The provided regular expression is using multiline anchors (^ or $), which may present a security risk. Did you mean to use \A and \z, or forgot to add the :multiline => true option?

这是什么意思?我该如何解决?


你试过了/\.(gif|jpg|png)$/i吗?也许最后%r{}添加它自己$的。
Wukerplank

@Wukerplank我不这么认为。%r{\.(gif|jpg|png)$}i #=> /\.(gif|jpg|png)$/i%r{\.(gif|jpg|png)}i #=> /\.(gif|jpg|png)/i
sawa

是的,但这并没有帮助
malcoauri 2013年

1
@wukerplank为什么我们要猜测?在红宝石中,我们必须irb帮助我们确定:)
mlibby 2014年

3
您需要删除png之后的$,表示这是最后一项,并替换为\ z
Gary

Answers:


158

^并且$“行起点”和“行终点锚点。虽然\A\z是永久开始字符串和结束串的锚。
看到不同:

string = "abcde\nzzzz"
# => "abcde\nzzzz"

/^abcde$/ === string
# => true

/\Aabcde\z/ === string
# => false

所以Rails的告诉你,“你确定你想使用^$?难道你不希望使用\A\z呢?”

还有更多的是对产生此警告的轨道安全问题在这里


3
解决不必要的口语化问题
xaxxon

2
解释了它要问的内容,但没有回答如何解决它。我想如果要使用^和$修复它的方法是在类的顶部添加:multiline => true?
isimmons

@isimmons通过添加:multiline => true仅可修复警告:Rails,您知道您在做什么。
oldgod 2013年

6
答案就在那里:使用\ A和\ z而不是^和$,因为在Ruby中,^和$仅匹配换行符而不是字符串的开头和结尾,这允许javascript漏洞通过测试。
JohnMerlino 2014年

31

出现此警告是因为您的验证规则容易受到javascript注入的攻击。

在您的情况下,\.(gif|jpg|png)$匹配到该行的末尾。因此,您的规则将验证此值为pic.png\nalert(1);true:

"test.png\n<script>alert(1)</script>" === /\.(gif|jpg|png)$/i
# => true

"test.png\n<script>alert(1)</script>" === /\.(gif|jpg|png)\z/i
# => false

阅读方法:


最好的,希望我们可以使这个成为公认的答案。
mlibby 2014年

2

regexp问题不在设计中,而是存在于config / initializers / devise.rb中。更改:

# Regex to use to validate the email address
config.email_regexp = /^([\w\.%\+\-]+)@([\w\-]+\.)+([\w]{2,})$/i

至:

# Regex to use to validate the email address
  config.email_regexp = /\A([\w\.%\+\-]+)@([\w\-]+\.)+([\w]{2,})\Z/i

1

警告是告诉您类似以下的字符串将通过验证,但可能不是您想要的:

test = "image.gif\nthis is not an image"
re = /\.(gif|jpg|png)$/i
re.match(test) #=> #<MatchData ".gif" 1:"gif">

两者^$匹配任何行的开始/结束,而不是字符串的开始/结束。\A并分别\z匹配完整字符串的开头和结尾。

re = /\.(gif|jpg|png)\z/i
re.match(test) #=> nil

该警告的第二部分(“或忘了加:多=> true选项”)是告诉你,如果你真的想要的行为,^并且$你可以简单地沉默警告传递:multiline选项。


那你去:multiline哪儿了?
皮蒂科斯

-1

如果为了安全起见,Ruby希望看到\z而不是$符号符号,则需要将其交给他,那么代码将如下所示:

validates :image_url, allow_blank: true, format: {with: %r{\.(gif|jpg|png)\z}i, message: 'URL must point to GIF, JPG, PNG.'}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.