क्वेरी की तरह सुरक्षित ActiveRecord


85

मैं LIKE क्वेरी लिखने की कोशिश कर रहा हूँ।

मैंने पढ़ा है कि शुद्ध स्ट्रिंग क्वायर सुरक्षित नहीं हैं, हालांकि मुझे कोई भी दस्तावेज नहीं मिला जो यह बताता हो कि सुरक्षित LIKE Hash Query कैसे लिखा जाता है।

क्या यह संभव है? क्या मुझे मैन्युअल रूप से SQL इंजेक्शन से बचाव करना चाहिए?


जवाबों:


166

यह सुनिश्चित करने के लिए कि आपकी क्वेरी स्ट्रिंग ठीक से साफ हो गई है, अपनी स्थितियों का वर्णन करने के लिए सरणी या हैश क्वेरी सिंटैक्स का उपयोग करें:

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 इंजेक्शन" मनमाना नहीं है, लेकिन फिर भी अप्रत्याशित रूप से कार्य कर सकता है।
बेनी चेर्नियाव्स्की-पास्किन

@ BeniCherniavsky-Paskin: यह पूरा बिंदु है, आप बचना नहीं चाहते %क्योंकि %यह LIKEवाक्य रचना का हिस्सा है । यदि आप बच गए %तो परिणाम मूल रूप से एक सामान्य =प्रश्न होगा।
स्पिकमैन

1
ठीक है, आप अपने पैटर्न टेम्प्लेट में% वाइल्डकार्ड का उपयोग करना चाहते हैं, लेकिन वह पैटर्न queryवेरिएबल वाला पैराड्राइक है, और कई मामलों में आप वस्तुतः स्ट्रिंग को queryवेरिएबल में मैच करना चाहते हैं , queryLIKE मेटाचैकर्स का उपयोग करने की अनुमति नहीं देते हैं । चलो एक और अधिक यथार्थवादी उदाहरण लेते हैं कि% ...%: स्ट्रिंग्स में एक पथ जैसी संरचना होती है, और आप मिलान करने का प्रयास करते हैं /users/#{user.name}/tags/%। अब अगर मैं अपना उपयोगकर्ता नाम की व्यवस्था होने के लिए fr%d%, मैं निरीक्षण करने के लिए सक्षम हो जाएगा fredऔर fridaके टैग ...
बेनी Cherniavsky-Paskin

2
ठीक है, मैं जो कुछ भी कर रहा हूं, इस सवाल का संयोजन stackoverflow.com/questions/5709887/… के साथ कर रहा हूं, जो बताता है sanitize_sql_like()
बेनी चेर्नियव्स्की-पास्किन

2
@ BeniCherniavsky-Paskin अब मैं समझता हूं कि आप कहां से आ रहे हैं और आप सही हैं। मैंने उस मुद्दे को संबोधित करने के लिए अपना जवाब अपडेट किया।
स्पिकमैन

34

Arel का उपयोग करके आप यह सुरक्षित और पोर्टेबल क्वेरी कर सकते हैं:

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

1
यह एक बेहतर समाधान है, क्योंकि Arel sql-db-agnostic है और इसमें कुछ आंतरिक इनपुट समाशोधन हैं। जहां तक ​​कोड-स्टाइल, IMHO की बात है, तो यह बहुत अधिक सुपाठ्य और सुसंगत है।
एंड्रयू मूर

आप इसे कैसे नकारते हैं? (यानी LIKE नहीं) Model.where(title.matches("%#{query}%").not)काम करता है, हालाँकि उत्पन्न SQL थोड़ा अजीब है:WHERE (NOT (`models`.`title` LIKE '%foo%'))
Noach Magedman

आह ... मिल गया। 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 '%'"

@NoachMagedman या Model.where.not(title.matches("%#{query}%"))does_not_matchहालांकि, बेहतर पढ़ता है।
एलक्विमिस्टा

7

PostgreSQL के लिए यह होगा

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

1

तुम कर सकते हो

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

1
@mikkeljuhl कृपया मेरे उत्तर को ध्यान से देखें।
संतोष

0

यदि नेस्टेड एसोसिएशन पर खोज क्वेरी करने वाला कोई भी व्यक्ति यह कोशिश करता है:

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अपने मॉडल के नाम के साथ बदलना न भूलें

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.