Sichere ActiveRecord-ähnliche Abfrage


84

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?


Antworten:


165

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 querydie Maßnahmen enthalten können %Zeichen , dann müssen Sie sanitize querymit sanitize_sql_likeersten:

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

Dies kann %in der Abfragezeichenfolge nicht maskiert werden. Es ist keine willkürliche "SQL-Injection", kann aber dennoch unerwartet funktionieren.
— Beni Cherniavsky-Paskin

@ BeniCherniavsky-Paskin: Das ist der springende Punkt, du willst dem nicht entkommen, %weil das %Teil der LIKESyntax ist. Wenn Sie dem entkommen sind, %wäre das Ergebnis im Grunde eine normale =Abfrage.
— Spickermann

1
Richtig, SIE möchten% Platzhalter in Ihrer Mustervorlage verwenden, aber dieses Muster ist mit queryVariable parametrisiert , und in vielen Fällen möchten Sie buchstäblich mit der Zeichenfolge in queryVariable übereinstimmen und dürfen keine queryLIKE-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, kann fr%d%ich die Tags von fredund beobachten frida...
— Beni Cherniavsky-Paskin

2
OK, ich möchte diese Frage mit stackoverflow.com/questions/5709887/… kombinieren, was darauf hindeutet sanitize_sql_like().
— Beni Cherniavsky-Paskin

2
@ BeniCherniavsky-Paskin Jetzt verstehe ich, woher du kommst und du hast recht. Ich habe meine Antwort aktualisiert, um dieses Problem zu beheben.
— Spickermann

34

Mit Arel können Sie diese sichere und tragbare Abfrage durchführen:

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

1
Dies ist die bevorzugte Lösung, da Arel sql-db-agnostisch ist und einige interne Eingangsbereinigungen aufweist. Auch ist viel besser lesbar und konsistent, was den Codestil betrifft, IMHO.
— Andrew Moore

Wie negierst du das? (dh NICHT WIE) Model.where(title.matches("%#{query}%").not)funktioniert, obwohl das generierte SQL etwas umständlich ist:WHERE (NOT (`models`.`title` LIKE '%foo%'))
— Noach Magedman

Aah ... habe es gefunden. Model.where(title.does_not_match("%#{query}%")). Erzeugt: WHERE (`models`.`title` NOT LIKE '%foo%')
— Noach Magedman

Vorsicht - dies kann nicht %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 '%'"
— bereinigen

@NoachMagedman oder Model.where.not(title.matches("%#{query}%")). does_not_matchliest sich aber besser, IMO.
— Elquimista

7

Für PostgreSQL wird es sein

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

1

Du kannst tun

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

1
@mikkeljuhl Bitte schau dir meine Antwort genau an.
— Santhosh

0

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 AssociatedModelNameIhren Modellnamen zu ersetzen

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.