ฉันกำลังพยายามเขียนข้อความค้นหา LIKE
ฉันอ่านแล้วว่าคำถามสตริงที่แท้จริงไม่ปลอดภัย แต่ฉันไม่พบเอกสารใด ๆ ที่อธิบายวิธีการเขียน LIKE Hash Query ที่ปลอดภัย
เป็นไปได้ไหม? ฉันควรป้องกัน SQL Injection ด้วยตนเองหรือไม่
ฉันกำลังพยายามเขียนข้อความค้นหา LIKE
ฉันอ่านแล้วว่าคำถามสตริงที่แท้จริงไม่ปลอดภัย แต่ฉันไม่พบเอกสารใด ๆ ที่อธิบายวิธีการเขียน LIKE Hash Query ที่ปลอดภัย
เป็นไปได้ไหม? ฉันควรป้องกัน SQL Injection ด้วยตนเองหรือไม่
คำตอบ:
เพื่อให้แน่ใจว่าสตริงการสืบค้นของคุณได้รับการทำความสะอาดอย่างถูกต้องให้ใช้อาร์เรย์หรือไวยากรณ์ของการสืบค้นแฮชเพื่ออธิบายเงื่อนไขของคุณ:
Foo.where("bar LIKE ?", "%#{query}%")
หรือ:
Foo.where("bar LIKE :query", query: "%#{query}%")
หากเป็นไปได้ว่าquery
อาจรวมถึง%
ตัวละครคุณต้องฆ่าเชื้อquery
ด้วยสิ่งนี้sanitize_sql_like
ก่อน:
Foo.where("bar LIKE ?", "%#{sanitize_sql_like(query)}%")
Foo.where("bar LIKE :query", query: "%#{sanitize_sql_like(query)}%")
%
ในสตริงแบบสอบถาม ไม่ใช่ "การแทรก SQL" ตามอำเภอใจ แต่ก็ยังอาจทำงานได้โดยไม่คาดคิด
%
เพราะ%
เป็นส่วนหนึ่งของLIKE
ไวยากรณ์ ถ้าคุณหนี%
ผลลัพธ์ก็จะเป็น=
แบบสอบถามปกติ
query
ตัวแปรและในหลาย ๆ กรณีคุณต้องการจับคู่สตริงในquery
ตัวแปรอย่างแท้จริงไม่อนุญาตให้query
ใช้ตัวอักษรLIKE ลองมาเป็นตัวอย่างที่สมจริงมากขึ้นว่า% ... %: /users/#{user.name}/tags/%
สตริงมีเส้นทางเช่นโครงสร้างและคุณพยายามที่จะแข่งขัน ตอนนี้ถ้าผมจัดชื่อผู้ใช้ของฉันจะfr%d%
ฉันจะสามารถที่จะสังเกตfred
และfrida
's แท็ก ...
sanitize_sql_like()
ซึ่งแสดงให้เห็น
การใช้ Arel คุณสามารถดำเนินการสืบค้นที่ปลอดภัยและพกพาได้:
title = Model.arel_table[:title]
Model.where(title.matches("%#{query}%"))
Model.where(title.matches("%#{query}%").not)
งานได้แม้ว่า SQL ที่สร้างขึ้นจะดูอึดอัดเล็กน้อย:WHERE (NOT (`models`.`title` LIKE '%foo%'))
Model.where(title.does_not_match("%#{query}%"))
. สร้าง: WHERE (`models`.`title` NOT LIKE '%foo%')
%
ในอินพุตที่ไม่น่าเชื่อถือ: >> 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
อ่านได้ดีขึ้นแม้ว่า IMO
สำหรับ PostgreSQL จะเป็น
Foo.where("bar ILIKE ?", "%#{query}%")
คุณทำได้
MyModel.where(["title LIKE ?", "%#{params[:query]}%"])
ในกรณีที่ใครก็ตามที่ทำการค้นหาเกี่ยวกับการเชื่อมโยงแบบซ้อนกันให้ลองทำดังนี้
Model.joins(:association).where(
Association.arel_table[:attr1].matches("%#{query}%")
)
สำหรับหลายแอตทริบิวต์ลองสิ่งนี้:
Model.joins(:association).where(
AssociatedModelName.arel_table[:attr1].matches("%#{query}%")
.or(AssociatedModelName.arel_table[:attr2].matches("%#{query}%"))
.or(AssociatedModelName.arel_table[:attr3].matches("%#{query}%"))
)
อย่าลืมแทนที่AssociatedModelName
ด้วยชื่อรุ่นของคุณ