Регулярные выражения с проверками в RoR 4
Существует следующий код:
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?
Что это значит? Как я могу это исправить?
Ответы
Ответ 1
^
и $
начинаются с строк и End строчных. В то время как \A
и \z
являются константами Start строковых и End строковых.
См. Разницу:
string = "abcde\nzzzz"
# => "abcde\nzzzz"
/^abcde$/ === string
# => true
/\Aabcde\z/ === string
# => false
Итак, Rails сообщает вам: "Вы действительно хотите использовать ^
и $
? Вместо этого вы не хотите использовать \A
и \z
?
По соображениям безопасности, связанным с рельсами, существует больше, чем это предупреждение здесь.
Ответ 2
Это предупреждение возникает из-за того, что ваше правило проверки уязвимо для инъекции 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
Прочитайте действия:
Ответ 3
Предупреждение сообщает вам, что строки, подобные приведенным ниже, пройдут проверку, но это, вероятно, не то, что вы хотите:
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
Вторая часть предупреждения ( "или забыли добавить: multiline = > true option" ) сообщает вам, что если вы действительно хотите поведение ^
и $
, вы можете просто отключить предупреждение, передающее :multiline
.
Ответ 4
Проблема regexp не в разработке, а скорее в config/initializers/devise.rb. Изменение:
# Regex to use to validate the email address
config.email_regexp = /^([\w\.%\+\-]+)@([\w\-]+\.)+([\w]{2,})$/i
to:
# Regex to use to validate the email address
config.email_regexp = /\A([\w\.%\+\-]+)@([\w\-]+\.)+([\w]{2,})\Z/i
Ответ 5
Если Ruby хочет видеть \z
вместо знака символа $
, для обеспечения безопасности вам нужно передать его ему, тогда код будет выглядеть так:
validates :image_url, allow_blank: true, format: {with: %r{\.(gif|jpg|png)\z}i, message: 'URL must point to GIF, JPG, PNG.'}