Ich versuche, eine ähnliche Abfrage zu schreiben.
Ich habe gelesen, dass reine String-Anforderungen nicht sicher sind, konnte jedoch keine Dokumentation finden, die erklärt, wie eine sichere LIKE Hash-Abfrage geschrieben wird.
Ist es möglich? Sollte ich mich manuell gegen SQL Injection verteidigen?
ruby
activerecord
ruby-on-rails-4
Gal Weiss
quelle
quelle
Antworten:
Verwenden Sie das Array oder die Hash-Abfragesyntax, um sicherzustellen, dass Ihre Abfragezeichenfolge ordnungsgemäß bereinigt wird, um Ihre Bedingungen zu beschreiben:
Foo.where("bar LIKE ?", "%#{query}%")
oder:
Foo.where("bar LIKE :query", query: "%#{query}%")
Wenn es möglich ist , dass die
query
die Maßnahmen enthalten können%
Zeichen , dann müssen Sie sanitizequery
mitsanitize_sql_like
ersten:Foo.where("bar LIKE ?", "%#{sanitize_sql_like(query)}%") Foo.where("bar LIKE :query", query: "%#{sanitize_sql_like(query)}%")
quelle
%
in der Abfragezeichenfolge nicht maskiert werden. Es ist keine willkürliche "SQL-Injection", kann aber dennoch unerwartet funktionieren.%
weil das%
Teil derLIKE
Syntax ist. Wenn Sie dem entkommen sind,%
wäre das Ergebnis im Grunde eine normale=
Abfrage.query
Variable parametrisiert , und in vielen Fällen möchten Sie buchstäblich mit der Zeichenfolge inquery
Variable übereinstimmen und dürfen keinequery
LIKE-Metazeichen verwenden. Nehmen wir ein realistischeres Beispiel:% ...%: Die Zeichenfolgen haben eine pfadartige Struktur, und Sie versuchen, eine Übereinstimmung zu erzielen/users/#{user.name}/tags/%
. Wenn ich jetzt meinen Benutzernamen einstelle, kannfr%d%
ich die Tags vonfred
und beobachtenfrida
...sanitize_sql_like()
.Mit Arel können Sie diese sichere und tragbare Abfrage durchführen:
title = Model.arel_table[:title] Model.where(title.matches("%#{query}%"))
quelle
Model.where(title.matches("%#{query}%").not)
funktioniert, obwohl das generierte SQL etwas umständlich ist:WHERE (NOT (`models`.`title` LIKE '%foo%'))
Model.where(title.does_not_match("%#{query}%"))
. Erzeugt:WHERE (`models`.`title` NOT LIKE '%foo%')
%
in nicht vertrauenswürdigen Eingaben>> 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_match
liest sich aber besser, IMO.Für PostgreSQL wird es sein
Foo.where("bar ILIKE ?", "%#{query}%")
quelle
Du kannst tun
MyModel.where(["title LIKE ?", "%#{params[:query]}%"])
quelle
Falls jemand eine Suchabfrage für eine verschachtelte Zuordnung ausführt, versuchen Sie Folgendes:
Model.joins(:association).where( Association.arel_table[:attr1].matches("%#{query}%") )
Versuchen Sie für mehrere Attribute Folgendes:
Model.joins(:association).where( AssociatedModelName.arel_table[:attr1].matches("%#{query}%") .or(AssociatedModelName.arel_table[:attr2].matches("%#{query}%")) .or(AssociatedModelName.arel_table[:attr3].matches("%#{query}%")) )
Vergessen Sie nicht, durch
AssociatedModelName
Ihren Modellnamen zu ersetzenquelle