LIKE sorgu yazmaya çalışıyorum.
Saf dizgi sorgularının güvenli olmadığını okudum, ancak Hash Query GİBİ güvenli yazmayı açıklayan herhangi bir belge bulamadım.
Mümkün mü? SQL Injection'a karşı manuel olarak savunma yapmalı mıyım?
LIKE sorgu yazmaya çalışıyorum.
Saf dizgi sorgularının güvenli olmadığını okudum, ancak Hash Query GİBİ güvenli yazmayı açıklayan herhangi bir belge bulamadım.
Mümkün mü? SQL Injection'a karşı manuel olarak savunma yapmalı mıyım?
Yanıtlar:
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)}%")
%, sorgu dizesinde kaçamaz . Bu rastgele bir "SQL enjeksiyonu" değildir, ancak yine de beklenmedik şekilde çalışabilir.
%çünkü sözdiziminin bir %parçası LIKE. Eğer kaçtıysanız, %sonuç temelde normal bir =sorgu olacaktır.
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 ...
sanitize_sql_like().
Arel'i kullanarak bu güvenli ve taşınabilir sorguyu gerçekleştirebilirsiniz:
title = Model.arel_table[:title]
Model.where(title.matches("%#{query}%"))
Model.where(title.matches("%#{query}%").not)çalışıyor, ancak oluşturulan SQL biraz garip olsa da:WHERE (NOT (`models`.`title` LIKE '%foo%'))
Model.where(title.does_not_match("%#{query}%")). Oluşturur: WHERE (`models`.`title` NOT LIKE '%foo%')
%, 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 '%'"
Model.where.not(title.matches("%#{query}%")). does_not_matchIMO daha iyi okur.
İç 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