Wyrażenia regularne z walidacją w RoR 4

83

Jest następujący kod:

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

Działa, ale kiedy spróbuję go przetestować za pomocą „testu rake”, wyłapię tę wiadomość:

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?

Co to znaczy? Jak mogę to naprawić?

malcoauri
źródło
Czy próbowałeś /\.(gif|jpg|png)$/i? Może na końcu %r{}dodaje swój własny $.
Wukerplank,
@Wukerplank Nie sądzę. %r{\.(gif|jpg|png)$}i #=> /\.(gif|jpg|png)$/i, %r{\.(gif|jpg|png)}i #=> /\.(gif|jpg|png)/i.
sawa
Tak, ale to nie pomogło
malcoauri
1
@wukerplank, dlaczego zgadujemy? w rubinie musimy irbnam pomóc wiedzieć na pewno :)
mlibby
3
Musisz usunąć znak $ po png), który wskazuje, że jest to ostatni element i zastąpić go \ z
Gary

Odpowiedzi:

158

^i $to start z linii i End Of Line kotwic. Choć \Ai \zsą trwałe start String i koniec sznurka kotwic.
Zobacz różnicę:

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

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

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

Więc Rails mówi ci: "Czy na pewno chcesz użyć ^i $? Nie chcesz użyć zamiast tego \Ai \z?"

Jest bardziej na obawy zabezpieczeń szyn, który generuje to ostrzeżenie tutaj .

starszybóg
źródło
3
naprawianie niepotrzebnego kolokwializmu
xaxxon
2
wyjaśnia, o co pyta, ale nie wyjaśnia, jak to naprawić. Przypuszczam, że jeśli chcesz użyć ^ i $, sposobem na naprawienie tego jest dodanie: multiline => true na początku klasy?
isimmons
@isimmons Dodając :multiline => true, naprawiasz tylko ostrzeżenie, że Railsy wiesz, co robisz.
oldgod,
6
Odpowiedź jest taka: używa się \ A i \ z zamiast ^ i $, ponieważ w Rubim ^ i $ pasują tylko do znaku nowej linii, a nie początku i końca ciągu, co pozwala exploitowi javascript przejść test.
JohnMerlino,
31

To ostrzeżenie pojawia się, ponieważ reguła weryfikacji jest podatna na wstrzyknięcie kodu JavaScript.

W twoim przypadku \.(gif|jpg|png)$mecze do końca linii. Twoja reguła potwierdzi tę wartość pic.png\nalert(1);jako prawdziwą:

"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

Przeczytaj akty:

ole
źródło
Najlepsze z całej grupy, żałuję, że nie możemy uczynić tego akceptowaną odpowiedzią.
mlibby
2

Problem regexp nie jest wymyślony, ale raczej żyje w config / initializers / devise.rb. Zmiana:

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

do:

# Regex to use to validate the email address
  config.email_regexp = /\A([\w\.%\+\-]+)@([\w\-]+\.)+([\w]{2,})\Z/i
mcr
źródło
1

Ostrzeżenie mówi ci, że łańcuchy takie jak poniższe przejdą walidację, ale prawdopodobnie nie jest to to, czego chcesz:

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

Oba ^i $dopasowuje początek / koniec dowolnego wiersza, a nie początek / koniec ciągu. \Ai \zdopasowuje odpowiednio początek i koniec pełnego ciągu.

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

Druga część ostrzeżenia („lub zapomniałeś dodać: multiline => opcja true”) mówi ci, że jeśli rzeczywiście chcesz zachowanie ^i $możesz po prostu wyciszyć ostrzeżenie, przekazując tę :multilineopcję.

yonosoytu
źródło
Więc gdzie przechodzisz :multiline?
Pithikos
-1

Jeśli Ruby chce widzieć \zzamiast $znaku symbolu, ze względów bezpieczeństwa, musisz mu go podać, wtedy kod wyglądałby tak:

validates :image_url, allow_blank: true, format: {with: %r{\.(gif|jpg|png)\z}i, message: 'URL must point to GIF, JPG, PNG.'}
max
źródło