কেন কেবল প্যারামিটারযুক্ত প্রশ্নগুলি ত্রুটি ফেরায় না?


22

এসকিউএল ইনজেকশন একটি অত্যন্ত গুরুতর সুরক্ষা সমস্যা, কারণ এটি এত সহজেই ভুল হওয়া সহজ: ব্যবহারকারীর ইনপুটকে অন্তর্ভুক্ত করে একটি ক্যোয়ারী তৈরি করার সুস্পষ্ট, স্বজ্ঞাত উপায় আপনাকে দুর্বল করে দেয় এবং এটিকে প্রশমিত করার সঠিক উপায়টি আপনাকে প্যারামিটারাইজড সম্পর্কে জানতে হবে প্রশ্নগুলি এবং এসকিউএল ইঞ্জেকশনটি প্রথমে।

আমার কাছে মনে হয় এটির সমাধানের সুস্পষ্ট উপায়টি হ'ল সুস্পষ্ট (তবে ভুল) বিকল্পটি বন্ধ করে দেওয়া হবে: ডাটাবেস ইঞ্জিনটি ঠিক করুন যাতে প্যারামিটারের পরিবর্তে তার কোথাও ক্লোডে হার্ড-কোডড মান ব্যবহার করে এমন কোনও কোয়েরি একটি সুন্দর, বর্ণনামূলক ফিরিয়ে দেয় পরিবর্তে পরামিতি ব্যবহার করার নির্দেশ দিচ্ছে ত্রুটি বার্তা। এতে অবশ্যই একটি অপ্ট-আউট বিকল্প থাকা দরকার যাতে প্রশাসনিক সরঞ্জামগুলি থেকে অ্যাড-হক কোয়েরির মতো জিনিসগুলি এখনও সহজেই চলতে পারে তবে এটি ডিফল্টরূপে সক্ষম করা উচিত।

এটি থাকার ফলে প্রায় রাতারাতি এসকিউএল ইঞ্জেকশন শীতল হয়ে যাবে, তবে যতদূর আমি জানি, কোনও আরডিবিএমএস আসলে এটি করে না। না করার কোনও ভাল কারণ আছে কি?


22
bad_ideas_sql = 'SELECT title FROM idea WHERE idea.status == "bad" AND idea.user == :mwheeler'একক ক্যোয়ারিতে হার্ড-কোডড এবং প্যারামিটারাইজড মান উভয়ই থাকবে - এটি ধরার চেষ্টা করুন! আমি মনে করি এই জাতীয় মিশ্র প্রশ্নের জন্য বৈধ ব্যবহারের কেস রয়েছে।
আমন

6
আজ থেকে রেকর্ড নির্বাচন সম্পর্কে কীSELECT * FROM jokes WHERE date > DATE_SUB(NOW(), INTERVAL 1 DAY) ORDER BY score DESC;
জয়দি

10
@ ম্যাসনওহিলার দুঃখিত, আমার অর্থ ছিল "এটির অনুমতি দেওয়ার চেষ্টা করুন" ” মনে রাখবেন এটি নিখুঁতভাবে প্যারামিটারাইজড এবং এসকিউএল ইঞ্জেকশনে ভোগেন না। তবে, ডাটাবেস ড্রাইভার বলতে পারবেন না যে আক্ষরিক "bad"সত্যই আক্ষরিক নাকি স্ট্রিং কন্টেটিংয়ের ফলে এসেছিল resulted আমি যে দুটি সমাধান দেখতে পাচ্ছি তা হয় এসকিউএল এবং অন্যান্য স্ট্রিং-এম্বেডড ডিএসএল (হ্যাঁ দয়া করে) থেকে মুক্তি পাচ্ছে, বা প্যারামিটারাইজড কোয়েরিগুলি (উম্ম, না) ব্যবহার করার চেয়ে স্ট্রিং কনটেন্টেশন আরও বিরক্তিকর এমন ভাষাগুলি প্রচার করছে।
আমন

4
এবং আরডিবিএমএস কীভাবে এটি করবে কিনা তা সনাক্ত করবে? এটি একটি রাতভর ইন্টারেক্টিভ এসকিউএল প্রম্পট ব্যবহার করে আরডিবিএমএস অ্যাক্সেস করা অসম্ভব করে তুলবে ... আপনি আর কোনও সরঞ্জাম ব্যবহার করে ডিডিএল বা ডিএমএল কমান্ড প্রবেশ করতে সক্ষম হবেন না।
আগমন

8
একটি অর্থে আপনি এটি করতে পারেন: রানটাইম এ মোটেও এসকিউএল কোয়েরিগুলি তৈরি করবেন না, এর পরিবর্তে একটি ওআরএম বা অন্য কিছু বিমূর্ত স্তর ব্যবহার করুন যা আপনাকে এসকিউএল কোয়েরিগুলি নির্মাণ করা প্রয়োজন এড়িয়ে চলে। ওআরএম এর আপনার প্রয়োজনীয় বৈশিষ্ট্যগুলি নেই? তারপরে এসকিউএল এমন একটি ভাষা যাঁরা এসকিউএল লিখতে চান তাদের জন্য উদ্দেশ্যে করা ভাষা, যার কারণেই এটি পুরোপুরি তাদের এসকিউএল লিখতে দেয়। মৌলিক সমস্যাটি হ'ল গতিশীলভাবে কোড উত্পন্ন করা দেখতে যতটা কঠিন তার চেয়ে শক্ত, তবে লোকেরা যেভাবেই হোক এটি করতে চায় এবং এমন পণ্যগুলিতে অসন্তুষ্ট হবে যা তাদের দেয় না।
স্টিভ জেসপ

উত্তর:


45

এমন অনেকগুলি ক্ষেত্রে রয়েছে যেখানে আক্ষরিক ব্যবহার করা সঠিক পন্থা।

পারফরম্যান্সের দৃষ্টিকোণ থেকে এমন সময় আসে যে আপনি আপনার প্রশ্নের মধ্যে আক্ষরিক চেয়েছিলেন। কল্পনা করুন যে আমার একটি বাগ ট্র্যাকার রয়েছে যেখানে এটি কর্মক্ষমতা সম্পর্কে চিন্তা করার জন্য যথেষ্ট পরিমাণে পরে গেলে আমি প্রত্যাশা করি যে সিস্টেমের 70% বাগগুলি "বন্ধ", 20% "উন্মুক্ত", 5% "সক্রিয়" এবং 5 থাকবে % অন্য কোনও স্থিতিতে থাকবে। আমি যুক্তিসঙ্গতভাবে ক্যোয়ারীটি রাখতে চাই যা সমস্ত সক্রিয় বাগগুলি হিসাবে ফিরে আসে

SELECT *
  FROM bug
 WHERE status = 'active'

statusবাইন্ড ভেরিয়েবল হিসাবে পাস করার চেয়ে । আমি যে মানটি পাস statusকরেছি তার উপর নির্ভর করে একটি আলাদা ক্যোয়ারী পরিকল্পনা চাই - আমি বন্ধ থাকা বাগগুলি এবং ইনডেক্স স্ক্যানটি ফিরিয়ে দিতে একটি টেবিল স্ক্যান করতে চাইstatusসক্রিয় returnণ ফেরত কলাম। এখন, বিভিন্ন ডাটাবেস এবং বিভিন্ন সংস্করণে পৃথক পদ্ধতির আলাদা আলাদা পদ্ধতি রয়েছে (আরও বা কম সফলভাবে) একই কোয়েরিকে বাইন্ড ভেরিয়েবলের মানের উপর নির্ভর করে একটি পৃথক ক্যোয়ারী পরিকল্পনা ব্যবহারের অনুমতি দেয়। তবে এটি একটি শালীন পরিমাণের জটিলতার পরিচয় দেয় যা কোনও ক্যোয়ারির পুনঃ-পার্সিংয়ে বিরক্ত করতে হবে বা নতুন বাইন্ডের ভেরিয়েবল মানের জন্য কোনও বিদ্যমান পরিকল্পনা পুনরায় ব্যবহার করতে হবে কিনা সেই সিদ্ধান্তের ভারসাম্য বজায় রাখতে হবে। একজন বিকাশকারীর জন্য, এই জটিলতা মোকাবেলা করা বোধগম্য হতে পারে। বা যখন আমার ডেটাটি অপ্টিমাইজারের চেয়ে আরও কী রকম দেখতে যাচ্ছে সে সম্পর্কে আরও তথ্য থাকবে তখন এটি অন্যরকম পথে জোর করে ফেলা অনুভূত হতে পারে।

একটি কোড জটিলতার দৃষ্টিকোণ থেকে, প্রচুর পরিমাণে এসকিউএল স্টেটমেন্টগুলিতে আক্ষরিক অর্থে থাকা সঠিক ধারণা তৈরি করে। উদাহরণস্বরূপ, যদি আপনার একটি zip_codeকলাম থাকে যেখানে 5 টি অক্ষরের জিপ কোড রয়েছে এবং কখনও কখনও অতিরিক্ত 4 ডিজিট থাকে তবে এটি এমন কিছু করার উপযুক্ত ধারণা তৈরি করে

SELECT substr( zip_code, 1, 5 ) zip,
       substr( zip_code, 7, 4 ) plus_four

সংখ্যার মানগুলির জন্য 4 টি পৃথক প্যারামিটারে পাস করার পরিবর্তে। এগুলি এমন কোনও জিনিস নয় যা এগুলির পরিবর্তিত হয় এবং এগুলি তাদের ভেরিয়েবলগুলি বাঁধাই কেবল কোডটি পড়ার সম্ভাব্যতা আরও জটিল করে তোলে এবং কেউ ভুল ক্রমে প্যারামিটারগুলি বেঁধে রাখে এবং একটি বাগ দিয়ে শেষ করে দেয় এমন সম্ভাবনা তৈরি করে।


12

এসকিউএল ইঞ্জেকশনটি ঘটে যখন কোনও কোয়েরির অন্যান্য অংশগুলির সাথে অবিশ্বস্ত ও অবৈধ উত্স থেকে পাঠ্যকে কনটেনেট করে কোয়েরি তৈরি করা হয়। যদিও এই জাতীয় জিনিসটি প্রায়শই স্ট্রিং লিটারেলের সাথে ঘটে তবে কেবল এটিই ঘটে না। সাংখ্যিক মান জন্য একটি ক্যোয়ারিতে একটি ব্যবহারকারী-প্রবেশ স্ট্রিং (যে এর নিতে পারে অনুমিত স্বাভাবিকভাবে স্ট্রিং লিটারেল সঙ্গে যুক্ত উদ্ধৃতি চিহ্ন ছাড়া একটি ক্যোয়ারী গঠনের একমাত্র ডিজিট) এবং অন্যান্য উপাদান সঙ্গে CONCATENATE; কোড যা ক্লায়েন্ট-সাইডের বৈধতার উপর অতিরিক্ত বিশ্বাস করে তার ক্ষেত্রে ক্ষেত্রের নামগুলি এইচটিএমএল কোয়েরি স্ট্রিং থেকে আসে। কোনও এসকিউএল কোয়েরি স্ট্রিংয়ের দিকে তাকানোর কোনও উপায় নেই কীভাবে এটি એસেম্বল হয়েছিল তা দেখতে পাবে।

কী গুরুত্বপূর্ণ তা কোনও এসকিউএল স্টেটমেন্টে স্ট্রিং লিটারেল রয়েছে কিনা তা নয়, বরং স্ট্রিংটিতে অবিশ্বস্ত উত্স থেকে বর্ণের কোনও ক্রম রয়েছে কিনা এবং এর জন্য বৈধতা পাঠাগারীতে সবচেয়ে ভাল পরিচালনা করা হবে যা অনুসন্ধান তৈরি করে। কোড লেখার জন্য সি # তে সাধারণত কোনও উপায় নেই যা স্ট্রিংকে আক্ষরিক অনুমতি দেয় তবে অন্য ধরণের স্ট্রিং এক্সপ্রেশনকে অনুমতি দেয় না, তবে একটি কোডিং-অনুশীলনের নিয়ম থাকতে পারে যার জন্য ক্যোয়ারী-বিল্ডিং ক্লাস ব্যবহার করে কোয়েরিগুলি তৈরি করা দরকার requires স্ট্রিং কনটেনটেশন এবং যে কেউ ক্যোয়ারী বিল্ডারের কাছে একটি অ-আক্ষরিক স্ট্রিং পাস করছে তাদের অবশ্যই এই জাতীয় পদক্ষেপের ন্যায্যতা প্রমাণ করতে পারে।


1
"এটি কি আক্ষরিক" এর অনুমান হিসাবে আপনি স্ট্রিংটি ইন্টার্নযুক্ত কিনা তা পরীক্ষা করতে পারেন।
কোডসইনচাউস

1
@ কোডসইনচওস: সত্য, এবং এই জাতীয় পরীক্ষাটি এই উদ্দেশ্যে যথেষ্ট যথাযথ হতে পারে, তবে যে কেউ রানটাইমের সময় স্ট্রিং তৈরির কারণী ছিল এমন একটি পদ্ধতি ব্যবহার করেছিল যা রানটাইম-উত্পন্ন স্ট্রিংটি অন্তর্ভুক্ত করার পরিবর্তে অ-আক্ষরিক স্ট্রিং গ্রহণ করে এবং ব্যবহার করে যে (অ-আক্ষরিক-স্ট্রিং পদ্ধতির একটি আলাদা নাম দেওয়া কোড পর্যালোচকদের এর সমস্ত ব্যবহারগুলি পরীক্ষা করা সহজ করে তোলে)।
সুপারক্যাট

মনে রাখবেন যে সি # তে এটি করার কোনও উপায় নেই, অন্য কয়েকটি ভাষায় এমন সুবিধা রয়েছে যা এটি সম্ভব করে তোলে (যেমন পার্লের কলঙ্কযুক্ত স্ট্রিং মডিউল)।
জুলু

আরও সংক্ষেপে, এটি একটি ক্লায়েন্ট সমস্যা, সার্ভারের সমস্যা নয়।
ব্লারফ্লায়

7
SELECT count(ID)
FROM posts
WHERE deleted = false

আপনি যদি এইগুলির ফলাফলগুলি আপনার ফোরামের ফুটারে রাখতে চান তবে প্রতিবার মিথ্যা বলার জন্য আপনাকে একটি ডামি প্যারামিটার যুক্ত করতে হবে। বা নিষ্পাপ ওয়েব প্রোগ্রামার কীভাবে সেই সতর্কতাটি অক্ষম করে এবং তারপরেও চালিয়ে যেতে পারে তা সন্ধান করে।

এখন আপনি বলতে পারেন আপনি এনামগুলির জন্য একটি ব্যতিক্রম যুক্ত করবেন তবে এটি কেবল গর্তটি আবার খোলে (আরও ছোট)। লোকদের উল্লেখ না করে প্রথমে varcharsতাদের ব্যবহার না করার জন্য শিক্ষিত হওয়া দরকার ।

ইনজেকশনটির আসল সমস্যাটি প্রোগ্রামিয়ালি ক্যোয়ারী স্ট্রিংটি তৈরি করা। এর সমাধান হ'ল একটি সঞ্চিত প্রক্রিয়া প্রক্রিয়া এবং এর ব্যবহার প্রয়োগ করা বা অনুমোদিত প্রশ্নের একটি শ্বেত তালিকা।


2
"প্যারাম্যাট্রাইজড কোয়েরিগুলি ব্যবহার করা - বা প্রথম স্থানে না জানা -" এটি ভুলে যাওয়া খুব সহজ is "এর জন্য যদি আপনার সমাধানটি" ​​প্রত্যেককে মনে রাখে - এবং প্রথম স্থানে জানায় - সঞ্চিত প্রকল্পগুলি ব্যবহার করে "তবে আপনি প্রশ্নের পুরো পয়েন্টটি মিস করছি।
ম্যাসন হুইলারের

5
আমি আমার কাজের সময় সঞ্চিত প্রক্রিয়াগুলির মাধ্যমে এসকিউএল ইঞ্জেকশনটি দেখেছি। দেখা যাচ্ছে যে সবকিছুর জন্য সঞ্চিত প্রক্রিয়া জাল করা খারাপ। সেখানে সর্বদা থাকে যে 0.5% সত্য গতিশীল ক্যোয়ারী (আপনি যেখানে পুরো ধারাটিকে প্যারামাইট্রাইজ করতে পারবেন না, কেবল কোনও টেবিলে যোগ দিতে দিন)।
জোশুয়া

এই উত্তরের উদাহরণে আপনি এর deleted = falseসাথে প্রতিস্থাপন করতে পারেন NOT deletedযা আক্ষরিক এড়ায়। তবে পয়েন্টটি সাধারণভাবে বৈধ।
স্মৃতি

5

টিএল; ডিআর : আপনাকে কেবলমাত্র অনুচ্ছেদে নয়, সমস্ত আক্ষরিক সীমাবদ্ধ করতে হবেWHERE । যে কারণে তারা না করে, এটি অন্যান্য সিস্টেম থেকে ডাটাবেসটিকে ডিকপল করার অনুমতি দেয়।

প্রথমত, আপনার ভিত্তি ত্রুটিযুক্ত। আপনি কেবলমাত্র WHEREধারাগুলিকে সীমাবদ্ধ রাখতে চান , তবে কেবলমাত্র ব্যবহারকারী ইনপুট যেতে পারে না। উদাহরণ স্বরূপ,

SELECT
    COUNT(CASE WHEN item_type = 'blender' THEN 1 END) as type1_count,
    COUNT(CASE WHEN item_type = 'television' THEN 1 END) AS type2_count)
FROM item

এটি এসকিউএল ইঞ্জেকশনের জন্যও সমান ঝুঁকিপূর্ণ:

SELECT
    COUNT(CASE WHEN item_type = 'blender' THEN 1 END) FROM item; DROP TABLE user_info; SELECT CASE(WHEN item_type = 'blender' THEN 1 END) as type1_count,
    COUNT(CASE WHEN item_type = 'television' THEN 1 END) AS type2_count)
FROM item

সুতরাং আপনি কেবল ধারাটিতে আক্ষরিক সীমাবদ্ধ করতে পারবেন না WHERE। আপনাকে সমস্ত আক্ষরিক সীমাবদ্ধ করতে হবে

এখন আমরা এই প্রশ্নটি রেখেই চলেছি, "কেন আক্ষরিকগুলিকে একেবারেই অনুমতি দেবেন?" মনের মধ্যে এই রাখুন: যখন রিলেশনাল ডাটাবেস সময় একটি বড় অংশ অন্য ভাষায় লিখিত একটি আবেদন নীচে ব্যবহার করা হয়, সেখানে নেই প্রয়োজন যে আপনি ডাটাবেস ব্যবহার করার জন্য অ্যাপ্লিকেশনটি কোড ব্যবহার করা আবশ্যক। এবং এখানে আমাদের একটি উত্তর আছে: কোড লেখার জন্য আপনার আক্ষরিক প্রয়োজন। অন্য একমাত্র বিকল্প হ'ল ডাটাবেস থেকে আলাদা কিছু ভাষাতে সমস্ত কোড রচনার প্রয়োজন। সুতরাং এগুলি থাকা আপনাকে সরাসরি ডাটাবেসে "কোড" (এসকিউএল) লেখার ক্ষমতা দেয়। এটি একটি মূল্যবান decoupling, এবং এটি আক্ষরিক ছাড়া অসম্ভব হবে। (আক্ষরিক ব্যতীত আপনার প্রিয় ভাষায় লেখার চেষ্টা করুন I'm আমি নিশ্চিত আপনি এটি কল্পনা করতে পারেন যে এটি কতটা কঠিন)

সাধারণ উদাহরণ হিসাবে, প্রায়শই তালিকাগুলির মান / চেহারা-সারণীগুলির তালিকাতে আক্ষরিক ব্যবহৃত হয়:

CREATE TABLE user_roles (role_id INTEGER, role_name VARCHAR(50));
INSERT INTO user_roles (1, 'normal');
INSERT INTO user_roles (2, 'admin');
INSERT INTO user_roles (3, 'banned');

এগুলি ব্যতীত, আপনাকে এই টেবিলটি বিশিষ্ট করতে অন্য প্রোগ্রামিং ভাষায় কোড লিখতে হবে । এসকিউএল এ সরাসরি করার ক্ষমতা মূল্যবান

তারপরে আমরা আরও একটি প্রশ্ন রেখেছি: প্রোগ্রামিং ভাষার ক্লায়েন্ট লাইব্রেরি কেন তখন তা করে না? এবং এখানে আমাদের খুব সাধারণ উত্তর রয়েছে: তারা ডাটাবেসের প্রতিটি সমর্থিত সংস্করণের জন্য পুরো ডাটাবেস পার্সারটিকে পুনরায় প্রয়োগ করতে পারে । কেন? কারণ আপনি প্রতিটি আক্ষরিক খুঁজে পেয়েছেন তার গ্যারান্টি ছাড়া অন্য কোনও উপায় নেই। নিয়মিত প্রকাশগুলি যথেষ্ট নয়। উদাহরণস্বরূপ: এতে পোস্টগ্র্যাস এসকিউএলএর 4 টি পৃথক আক্ষরিক রয়েছে:

SELECT $lit1$I'm a literal$lit1$||$lit2$I'm another literal $$ with nested string delimiters$$ $lit2$||'I''m ANOTHER literal'||$$I'm the last literal$$;

এটি করার চেষ্টা করা একটি রক্ষণাবেক্ষণ দুঃস্বপ্ন হতে পারে, বিশেষত যেহেতু বৈধ সিনট্যাক্স প্রায়শই ডাটাবেসের প্রধান প্রকাশের মধ্যে পরিবর্তিত হয়।

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