নিরাপদ অ্যাক্টিভেকর্ড যেমন কোয়েরি


89

আমি লাইক কোয়েরি লেখার চেষ্টা করছি।

আমি পড়েছি যে খাঁটি স্ট্রিং কোয়েস নিরাপদ নয়, তবে আমি নিরাপদে LIKE হাশ কোয়েরি কীভাবে লিখতে হয় তা ব্যাখ্যা করার মতো কোনও ডকুমেন্টেশন পাইনি।

এটা কি সম্ভব? এসকিউএল ইঞ্জেকশনের বিরুদ্ধে আমাকে নিজেই রক্ষা করা উচিত?


উত্তর:


168

আপনার ক্যোয়ারী স্ট্রিংটি সঠিকভাবে স্যানিটাইজড হয়েছে তা নিশ্চিত করতে আপনার অবস্থার বর্ণনা দিতে অ্যারে বা হ্যাশ ক্যোয়ারী বাক্য গঠন ব্যবহার করুন:

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)}%")

এটি ক্যোরির %স্ট্রিংয়ে পালাতে ব্যর্থ । এটি নির্বিচারে "এসকিউএল ইঞ্জেকশন" নয় তবে এখনও অপ্রত্যাশিতভাবে কাজ করতে পারে।
বেনি চেরনিয়াভস্কি-পাসকিন

@ বেনিচেরনিয়াভস্কি-পাসকিন: এটি সম্পূর্ণ বক্তব্য, আপনি এড়াতে চান না %কারণ %এটি LIKEসিনট্যাক্সের অংশ । আপনি যদি পরে পালাতে পারেন %তবে ফলাফলটি মূলত একটি সাধারণ =ক্যোয়ারী হবে।
চমত্কার

4
ঠিক আছে, আপনি আপনার প্যাটার্ন টেম্পলেটে% ওয়াইল্ডকার্ড ব্যবহার করতে চান তবে সেই প্যাটার্নটি queryভেরিয়েবলের সাথে প্যারাম্যাট্রাইজ করা হয়েছে এবং অনেক ক্ষেত্রে আপনি আক্ষরিক স্ট্রিংটির সাথে queryভেরিয়েবলের সাথে মিল রাখতে চান , queryLIKE metacharacters ব্যবহার করার অনুমতি দেবেন না । আসুন আরও বাস্তবসম্মত উদাহরণটি ধরুন যে% ...%: স্ট্রিংগুলির একটি পথের মতো কাঠামো রয়েছে এবং আপনি মিলের চেষ্টা করেন /users/#{user.name}/tags/%। এখন যদি আমি আমার ব্যবহারকারীর নামটি সাজানোর ব্যবস্থা করি তবে আমি fr%d%পর্যবেক্ষণ করতে fredএবং fridaতার ট্যাগগুলি দেখতে সক্ষম হবো ...
বেনি চেরনিয়াভস্কি-পাসকিন

4
ঠিক আছে, আমি পরে যা করছি তা এই প্রশ্নটিকে স্ট্যাকওভারফ্লো / প্রশ্নগুলি / ৫70০৯৮77/২ এর সাথে সংযুক্ত করছে যা প্রস্তাব দেয় sanitize_sql_like()
বেনি চেরনিয়াভস্কি-পাসকিন

4
@ বেনিচেরনিয়াভস্কি-পাসকিন এখন আমি বুঝতে পেরেছি আপনি কোথা থেকে এসেছেন এবং আপনি সঠিক। আমি এই সমস্যাটির সমাধানের জন্য আমার উত্তর আপডেট করেছি।
চমত্কার

36

আরেল ব্যবহার করে আপনি এই নিরাপদ এবং বহনযোগ্য কোয়েরি করতে পারেন:

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

4
এটিই অগ্রাধিকারযোগ্য সমাধান, যেহেতু আরেল স্ক্যাল-ডিবি-অজোনস্টিক এবং এর কিছুটা অভ্যন্তরীণ ইনপুট পরিস্কার করা রয়েছে। আইএমএইচও যতটা কোড-স্টাইল যায় ততই আরও স্পষ্টত এবং সামঞ্জস্যপূর্ণ।
অ্যান্ড্রু মুর

আপনি কীভাবে এটিকে অস্বীকার করবেন? (অর্থাত্ পছন্দ না) Model.where(title.matches("%#{query}%").not)কাজ করে, উত্পন্ন এসকিউএল কিছুটা বিশ্রী হলেও: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আইএমও যদিও আরও ভাল পড়া।
elquimista


1

আপনি করতে পারেন

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

4
@ মিক্কেলজুহল দয়া করে আমার উত্তরটি মনোযোগ সহকারে দেখুন।
সন্তোষ

1

যদি কেউ নেস্টেড সংস্থায় অনুসন্ধান অনুসন্ধান করে থাকে তবে এটি চেষ্টা করুন:

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আপনার মডেল নামটি প্রতিস্থাপন করতে ভুলবেন না

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.