ওয়েবসাইট বা অ্যাপ্লিকেশনে ব্যবহারকারী যখন কোনো তথ্য ইনপুট দেয়, তখন সেই ইনপুট সরাসরি SQL কোয়েরিতে জুড়ে দিলে বড় ধরনের নিরাপত্তা ত্রুটি তৈরি হতে পারে – একে বলে SQL Injection। একজন আক্রমণকারী সাধারণ ইনপুটের বদলে ক্ষতিকর SQL কোড পাঠিয়ে আপনার পুরো ডাটাবেস নিয়ন্ত্রণ নিতে পারে, ডেটা চুরি বা মুছেও ফেলতে পারে। SQLite-ও এই আক্রমণ থেকে মুক্ত নয়, বরং এটি স্ট্যাকড কোয়েরি (একসাথে একাধিক SQL স্টেটমেন্ট) সমর্থন করে বলে আক্রমণ আরও ভয়াবহ হতে পারে। এই পর্বে আমরা SQL Injection-এর ভয়াবহতা, কীভাবে এটি কাজ করে এবং নিরাপদে কোডিং করার কৌশল (প্যারামিটারাইজড কোয়েরি, এস্কেপিং, ভ্যালিডেশন) বিস্তারিত শিখব।
পূর্বপ্রস্তুতি:
- SQLite ইন্সটল থাকতে হবে (সিরিজের ৩য় পর্ব দেখুন)।
- সাধারণ প্রোগ্রামিং ধারণা (পিএইচপি বা পাইথন উদাহরণ বোঝার জন্য)।
- কোনো বিশেষ প্যাকেজ ইন্সটলের দরকার নেই – আমরা SQLite কমান্ড লাইন ও পাইথনের বিল্ট-ইন
sqlite3মডিউল ব্যবহার করব।
১. SQL Injection কী?
SQL Injection তখন ঘটে যখন ইউজার ইনপুট সঠিকভাবে ফিল্টার বা এস্কেপ না করেই ডাটাবেস কোয়েরির অংশ বানানো হয়। আক্রমণকারী এমন ইনপুট দেয় যা কোয়েরির যুক্তি বদলে দেয় বা সম্পূর্ণ নতুন SQL কমান্ড চালায়।
সরল দৃশ্যপট: ধরুন, একটি লগইন ফর্মে ইউজারনেম নেওয়া হয়:
sql
SELECT * FROM users WHERE username = 'ইউজার_ইনপুট';
ইউজার যদি ' OR '1'='1 টাইপ করে, তাহলে কোয়েরি দাঁড়ায়:
sql
SELECT * FROM users WHERE username = '' OR '1'='1';
এটি সব ইউজার ফেরত দেবে, লগইন বাইপাস হয়ে যাবে।
আরও ভয়ংকর: ইউজার যদি '; DROP TABLE users; -- দেয়, তাহলে SQLite-তে (যা মাল্টিপল স্টেটমেন্ট সাপোর্ট করে) কোয়েরি হবে:
sql
SELECT * FROM users WHERE username = ''; DROP TABLE users; --';
এটি ইউজার টেবিল মুছে ফেলবে।
২. উদাহরণ: দুর্বল পিএইচপি কোড ও আক্রমণ
নিচের পিএইচপি কোডটি দেখুন:
php
$name = $_GET['username'];
$db = new SQLiteDatabase('users.db');
$result = $db->query("SELECT * FROM users WHERE username = '$name'");
এখন যদি $name এর মান Qadir'; DELETE FROM users; -- হয়, তাহলে এক্সিকিউট হবে:
sql
SELECT * FROM users WHERE username = 'Qadir'; DELETE FROM users; --'
SQLite স্ট্যাকড কোয়েরি সমর্থন করে, তাই এটি DELETE FROM users চালিয়ে সব ইউজার ডিলিট করবে।
সতর্কতা: SQLite-তে মাল্টিপল স্টেটমেন্ট একসাথে চালানো যায় (যেমন sqlite3_exec() ফাংশন), তাই ইনজেকশন বড় বিপদ।
৩. প্রতিরোধের উপায়
৩.১ ইনপুট ভ্যালিডেশন
প্রথম প্রতিরক্ষা হলো ব্যবহারকারীর ইনপুট যাচাই করা। যেমন, ইউজারনেম শুধুমাত্র অক্ষর, সংখ্যা ও আন্ডারস্কোর এবং নির্দিষ্ট দৈর্ঘ্যের হতে পারে:
php
if (preg_match("/^\w{8,20}$/", $_GET['username'], $matches)){
// নিরাপদ
} else {
echo "username not accepted";
}
কিন্তু একা ভ্যালিডেশন যথেষ্ট নয়, কারণ অনেক সময় জটিল ইনপুট দরকার হয় (যেমন অ্যাপোস্ট্রফি)।
৩.২ প্যারামিটারাইজড কোয়েরি (Prepared Statements)
সবচেয়ে নিরাপদ পদ্ধতি হলো প্যারামিটারাইজড কোয়েরি বা Prepared Statement ব্যবহার করা। এতে ইউজার ডেটা কখনো সরাসরি SQL স্ট্রিংয়ে যোগ হয় না; বরং প্লেসহোল্ডার (? বা নামযুক্ত) ব্যবহার করে পরে বাইন্ড করা হয়। SQLite একে সম্পূর্ণরূপে সমর্থন করে।
পাইথন উদাহরণ (সঠিক):
python
import sqlite3
conn = sqlite3.connect('users.db')
cursor = conn.cursor()
username = input("Enter username: ")
cursor.execute("SELECT * FROM users WHERE username = ?", (username,))
এখন কেউ ইনজেকশন কোড দিলেও তা শুধু ডেটা হিসেবে গণ্য হবে, কোড হিসেবে নয়।
পিএইচপি-তে PDO প্রস্তুত বিবৃতি:
php
$stmt = $db->prepare("SELECT * FROM users WHERE username = :username");
$stmt->bindValue(':username', $name, SQLITE3_TEXT);
$result = $stmt->execute();
৩.৩ এস্কেপিং (কম পছন্দনীয়)
কিছু পুরনো API আছে যা এস্কেপিং ফাংশন দেয়, যেমন sqlite_escape_string()। এটি বিশেষ ক্যারেক্টার (যেমন কোটেশন) এস্কেপ করে, কিন্তু এটিকে পুরোপুরি নির্ভরযোগ্য বলা যায় না, এবং LIKE ক্লজের সাথে সমস্যা করতে পারে। Prepared Statement-ই আধুনিক ও নিরাপদ পন্থা।
php
$name = sqlite_escape_string($name);
$result = $db->query("SELECT * FROM users WHERE username = '$name'");
addslashes()কখনো SQLite-র জন্য ব্যবহার করবেন না; এটি অদ্ভুত ফল দিতে পারে।
৪. SQLite CLI-তে স্ট্যাকড কোয়েরির উদাহরণ
আমরা নিজেরা পরীক্ষা করে দেখতে পারি যে SQLite মাল্টিপল স্টেটমেন্ট একত্রে চালায়:
bash
sqlite3 :memory:
sql
CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT); INSERT INTO users VALUES (1, 'Rahim'); -- একসাথে একাধিক স্টেটমেন্ট (স্ট্যাকড) SELECT * FROM users; DELETE FROM users; SELECT 'injected';
এটি SELECT দেখানোর পর DELETE চালাবে এবং শেষে injected স্ট্রিং দেখাবে। এটিই প্রমাণ করে যে, যদি ইউজার ইনপুট এমন কিছু দেয়, তাহলে অনাকাঙ্ক্ষিত কমান্ড চলতে পারে।
৫. ডিরেক্টরি স্ট্রাকচার ও প্যাকেজ
এই পর্বে কোনো নির্দিষ্ট প্রজেক্ট স্ট্রাকচার নেই; আপনার অ্যাপ্লিকেশনের ফাইলের মধ্যে ডাটাবেস ফাইল থাকবে। নিরাপত্তার জন্য ডাটাবেস ফাইলকে ওয়েব-অ্যাক্সেসিবল ডিরেক্টরির বাইরে রাখা বাঞ্ছনীয়।
পাইথনের ক্ষেত্রে কোনো বাড়তি প্যাকেজ লাগবে না; পিএইচপি-তে SQLite3 এক্সটেনশন সচল থাকতে হবে।
৬. গুরুত্বপূর্ণ টিপস
- কখনোই ইউজার ইনপুট সরাসরি SQL-এ জুড়বেন না – এটি চূড়ান্ত নিয়ম।
- Prepared Statement ব্যবহার করুন – এটি SQL Injection সম্পূর্ণরূপে রোধ করে।
- ন্যূনতম সুবিধা নীতি: ডাটাবেস ইউজারকে কেবল প্রয়োজনীয় অনুমতি দিন (তবে SQLite ফাইলভিত্তিক, তাই ফাইল পারমিশন সঠিক রাখুন)।
- ORM ব্যবহার করলে (যেমন SQLAlchemy) আপনা-আপনি Prepared Statement হয়, তবে কাঁচা SQL লিখলে সতর্ক থাকুন।
- ত্রুটি বার্তা ব্যবহারকারীকে দেখাবেন না – এতে ডাটাবেস গঠন ফাঁস হতে পারে।
- নিয়মিত কোড রিভিউ ও টেস্টিং করুন।
৭. সম্পূর্ণ অনুশীলন সেশন (পাইথন নিরাপদ উদাহরণ)
ধরি, আমাদের একটি app.py আছে:
python
import sqlite3
def get_user(username):
conn = sqlite3.connect('users.db')
cursor = conn.cursor()
# নিরাপদ: প্যারামিটারাইজড কোয়েরি
cursor.execute("SELECT * FROM users WHERE username = ?", (username,))
return cursor.fetchone()
# ব্যবহার
user_input = input("Username: ")
print(get_user(user_input))
এমনকি যদি ইনপুট '; DROP TABLE users; -- হয়, কিছুই হবে না – এটি শুধু ওই অদ্ভুত ইউজারনেম খুঁজবে।
পরবর্তী পর্বে
আমরা শিখব SQLite EXPLAIN – কীভাবে কোয়েরি প্ল্যান বিশ্লেষণ করে পারফরম্যান্স অপ্টিমাইজ করা যায়।
লেখকের কথা: সিকিউরিটি কোনো ফিচার নয়, অভ্যাস। আজই আপনার কোডে Prepared Statement চালু করুন। বাংলায় SQLite শেখার এই সিরিজ আপনার ডাটাবেস জ্ঞানকে শক্ত ভিতের ওপর দাঁড় করাবে। পোস্টটি ভালো লাগলে শেয়ার করুন, এবং সব আপডেট পেতে ToLearnTeam.com সাবস্ক্রাইব করুন। কোনো প্রশ্ন বা মতামত জানাতে কমেন্ট করুন – আমরা উত্তর দিতে প্রস্তুত!
SQLite Full Course
- SQLite পরিচিতি ও ইন্সটলেশন গাইড – বাংলায় প্রথম ডাটাবেস তৈরি
- SQLite কী এবং কেন শিখবেন? সম্পূর্ণ ওভারভিউ ও কমান্ড ক্লাসিফিকেশন (DDL, DML, DQL)
- SQLite ইন্সটলেশন গাইড – Windows, Linux ও Mac-এ ধাপে ধাপে সেটআপ
- SQLite ডট কমান্ড (Dot Commands) – সম্পূর্ণ গাইড, আউটপুট ফরম্যাট ও sqlite_master
- SQLite সিনট্যাক্স (Syntax) – কেস সেনসিটিভিটি, কমেন্ট, সব কমান্ডের গঠন ও উদাহরণ
- SQLite ডেটা টাইপ (Data Type) – স্টোরেজ ক্লাস, টাইপ অ্যাফিনিটি, বুলিয়ান ও ডেট-টাইম
- SQLite ডেটাবেস তৈরি (Create Database) – ধাপে ধাপে গাইড, .dump এক্সপোর্ট ও রিস্টোর
- SQLite ATTACH DATABASE – একাধিক ডাটাবেস সংযুক্ত করার সম্পূর্ণ গাইড (বাংলা)
- SQLite DETACH DATABASE – সংযুক্ত ডাটাবেস বিচ্ছিন্ন করার পূর্ণাঙ্গ গাইড
- SQLite CREATE TABLE স্টেটমেন্ট – টেবিল তৈরি করার পূর্ণাঙ্গ গাইড (বাংলা)
- SQLite DROP TABLE স্টেটমেন্ট – টেবিল ডিলিট করার সম্পূর্ণ গাইড (বাংলা)
- SQLite INSERT INTO স্টেটমেন্ট – ডেটা ইনসার্ট করার সম্পূর্ণ গাইড (বাংলা)
- SQLite SELECT স্টেটমেন্ট – টেবিল থেকে ডেটা ফেচ করার সম্পূর্ণ গাইড (বাংলা)
- SQLite অপারেটর (Operators) – Arithmetic, Comparison, Logical, Bitwise (বাংলা টিউটোরিয়াল)
- SQLite এক্সপ্রেশন (Expressions) – বুলিয়ান, নিউমেরিক ও ডেট এক্সপ্রেশন (বাংলা টিউটোরিয়াল)
- SQLite AND ও OR অপারেটর – একাধিক শর্ত দিয়ে ডেটা ফিল্টার (বাংলা টিউটোরিয়াল)
- SQLite UPDATE Query – টেবিলের ডেটা পরিবর্তন করার সম্পূর্ণ গাইড (বাংলা)
- SQLite DELETE Query – টেবিল থেকে ডেটা মুছে ফেলার সম্পূর্ণ গাইড (বাংলা)
- SQLite LIKE Operator – প্যাটার্ন মিলিয়ে ডেটা খোঁজার সম্পূর্ণ গাইড (বাংলা)
- SQLite GLOB Operator – কেস-সেনসিটিভ প্যাটার্ন মিলিয়ে ডেটা খোঁজা (বাংলা)
- SQLite LIMIT Clause – ডেটা সীমিত করে আনার সম্পূর্ণ গাইড (বাংলা)
- SQLite ORDER BY ক্লজ – ডেটা সাজানোর সম্পূর্ণ গাইড (বাংলা)
- SQLite GROUP BY ক্লজ – ডেটা গ্রুপ করে বিশ্লেষণ করার সম্পূর্ণ গাইড (বাংলা)
- SQLite HAVING ক্লজ – গ্রুপের উপর শর্ত দিয়ে ডেটা ফিল্টার (বাংলা টিউটোরিয়াল)
- SQLite DISTINCT Keyword – ডুপ্লিকেট ডেটা বাদ দিয়ে ইউনিক ভ্যালু পাওয়া (বাংলা)
- SQLite PRAGMA কমান্ড – ডাটাবেস কনফিগারেশন ও সেটিংস (বাংলা টিউটোরিয়াল)
- SQLite Constraints – NOT NULL, DEFAULT, UNIQUE, PRIMARY KEY, CHECK (বাংলা টিউটোরিয়াল)
- SQLite JOINS – CROSS JOIN, INNER JOIN, LEFT OUTER JOIN (বাংলা টিউটোরিয়াল)
- SQLite UNION ও UNION ALL – একাধিক SELECT একত্রিত করার সম্পূর্ণ গাইড (বাংলা)
- SQLite NULL Values – NULL কী, IS NULL, IS NOT NULL (বাংলা টিউটোরিয়াল)
- SQLite ALIAS Syntax – টেবিল ও কলামের অস্থায়ী নাম (বাংলা টিউটোরিয়াল)
- SQLite Triggers – স্বয়ংক্রিয় ট্রিগার তৈরি, ব্যবহার ও মুছে ফেলা (বাংলা টিউটোরিয়াল)
- SQLite Indexes – CREATE, UNIQUE, COMPOSITE, DROP INDEX (বাংলা টিউটোরিয়াল)
- SQLite INDEXED BY Clause – নির্দিষ্ট ইনডেক্স ব্যবহার ও NOT INDEXED (বাংলা)
- SQLite ALTER TABLE Command – টেবিলের গঠন পরিবর্তন (বাংলা টিউটোরিয়াল)
- SQLite TRUNCATE TABLE Command – DELETE ও DROP দিয়ে টেবিল খালি করা (বাংলা)
- SQLite Views – ভার্চুয়াল টেবিল তৈরি, ব্যবহার ও ডিলিট (বাংলা টিউটোরিয়াল)
- SQLite Transactions – BEGIN, COMMIT, ROLLBACK ও ACID প্রপার্টি (বাংলা)
- SQLite Subqueries – SELECT, INSERT, UPDATE, DELETE-এ সাবকোয়েরি ব্যবহার (বাংলা টিউটোরিয়াল)
- SQLite AUTOINCREMENT – স্বয়ংক্রিয়ভাবে প্রাইমারি কি মান বৃদ্ধি (বাংলা টিউটোরিয়াল)
- SQLite SQL Injection – কী, কেন বিপজ্জনক ও প্রতিরোধের উপায় (বাংলা টিউটোরিয়াল)
- SQLite EXPLAIN ও EXPLAIN QUERY PLAN – কোয়েরি বিশ্লেষণ (বাংলা টিউটোরিয়াল)
- SQLite VACUUM – ডাটাবেস পরিষ্কার, স্পেস রিক্লেইম ও অটো-ভ্যাকুয়াম (বাংলা টিউটোরিয়াল)
- SQLite Date & Time ফাংশন – date(), time(), datetime(), julianday(), strftime() (বাংলা টিউটোরিয়াল)
- SQLite Useful Functions – COUNT, MAX, MIN, AVG, SUM, RANDOM, ABS, UPPER, LOWER, LENGTH (বাংলা টিউটোরিয়াল)
- SQLite C/C++ প্রোগ্রামিং – sqlite3_open, exec, close, callback (বাংলা টিউটোরিয়াল)
- SQLite PHP প্রোগ্রামিং – PHP-তে SQLite ডাটাবেস ব্যবহার (বাংলা টিউটোরিয়াল)
- SQLite Perl প্রোগ্রামিং – DBI/DBD::SQLite দিয়ে ডাটাবেস অপারেশন (বাংলা)
- SQLite Python প্রোগ্রামিং – sqlite3 মডিউল দিয়ে CRUD অপারেশন (বাংলা টিউটোরিয়াল)
- SQLite Quick Guide – বাংলায় পূর্ণাঙ্গ সংক্ষিপ্ত টিউটোরিয়াল (শেখার সহজ গাইড)
