Sorgu gibi Güvenli ActiveRecord


Yanıtlar:


168

Sorgu dizenizin düzgün bir şekilde temizlendiğinden emin olmak için, koşullarınızı açıklamak için diziyi veya karma sorgu sözdizimini kullanın:

Foo.where("bar LIKE ?", "%#{query}%")

veya:

Foo.where("bar LIKE :query", query: "%#{query}%")

O mümkünse queryiçerebilir %karakteri o zaman sterilize gerekir queryile sanitize_sql_likeilk:

Foo.where("bar LIKE ?", "%#{sanitize_sql_like(query)}%")
Foo.where("bar LIKE :query", query: "%#{sanitize_sql_like(query)}%")

Bu %, sorgu dizesinde kaçamaz . Bu rastgele bir "SQL enjeksiyonu" değildir, ancak yine de beklenmedik şekilde çalışabilir.
Beni Cherniavsky-Paskin

@ BeniCherniavsky-Paskin: Bütün mesele bu, kaçmak istemiyorsunuz %çünkü sözdiziminin bir %parçası LIKE. Eğer kaçtıysanız, %sonuç temelde normal bir =sorgu olacaktır.
spickermann

2
Doğru, desen şablonunuzda% joker karakterleri kullanmak istiyorsunuz, ancak bu desen querydeğişkenle parametreleştirilmiştir ve çoğu durumda query, queryLIKE meta karakterlerini kullanmaya izin vermemek için değişkendeki dizeyle tam anlamıyla eşleştirmek istersiniz . % ...% 'den daha gerçekçi bir örnek alalım: dizelerin yol benzeri bir yapısı var ve siz eşleştirmeye çalışıyorsunuz /users/#{user.name}/tags/%. Şimdi kullanıcı adımı olacak şekilde düzenlersem fr%d%, fredve fridaetiketlerini gözlemleyebileceğim ...
Beni Cherniavsky-Paskin

2
Tamam, peşinde olduğum şey bu soruyu öneren stackoverflow.com/questions/5709887/… ile birleştirmek sanitize_sql_like().
Beni Cherniavsky-Paskin

2
@ BeniCherniavsky-Paskin Şimdi nereden geldiğini anlıyorum ve haklısın. Cevabımı bu sorunu çözmek için güncelledim.
spickermann

36

Arel'i kullanarak bu güvenli ve taşınabilir sorguyu gerçekleştirebilirsiniz:

title = Model.arel_table[:title]
Model.where(title.matches("%#{query}%"))

1
Bu tercih edilen çözümdür, çünkü Arel sql-db-agnostiktir ve bazı dahili girdi temizliğine sahiptir. Ayrıca IMHO, kod stiline göre çok daha okunaklı ve tutarlı.
Andrew Moore

Bunu nasıl reddedersiniz? (yani GİBİ DEĞİL) Model.where(title.matches("%#{query}%").not)çalışıyor, ancak oluşturulan SQL biraz garip olsa da:WHERE (NOT (`models`.`title` LIKE '%foo%'))
Noach Magedman

Aah ... buldum. Model.where(title.does_not_match("%#{query}%")). Oluşturur: WHERE (`models`.`title` NOT LIKE '%foo%')
Noach Magedman

Dikkatli olun - bu %, güvenilmeyen girdileri temizleyemez : >> ActiveRecord::VERSION::STRING => "5.2.3" >> field = Foo.arel_table[:bar] >> Foo.where(field.matches('%')).to_sql => "SELECT `foos`.* FROM `foos` WHERE `foos`.`bar` LIKE '%'"
vjt

@NoachMagedman veya Model.where.not(title.matches("%#{query}%")). does_not_matchIMO daha iyi okur.
elquimista

7

PostgreSQL için

Foo.where("bar ILIKE ?", "%#{query}%") 

1

Yapabilirsin

MyModel.where(["title LIKE ?", "%#{params[:query]}%"])

1
@mikkeljuhl Lütfen cevabıma dikkatlice bakın.
Santhosh

1

İç içe geçmiş ilişkilendirmede arama sorgusu yapan biri varsa şunu deneyin:

Model.joins(:association).where(
   Association.arel_table[:attr1].matches("%#{query}%")
)

Birden çok özellik için şunu deneyin:

Model.joins(:association).where(
  AssociatedModelName.arel_table[:attr1].matches("%#{query}%")
    .or(AssociatedModelName.arel_table[:attr2].matches("%#{query}%"))
    .or(AssociatedModelName.arel_table[:attr3].matches("%#{query}%"))
)
 

AssociatedModelNameModel adınızla değiştirmeyi unutmayın

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.