Node.js ও Express-এ এসকিউএল ইনজেকশন প্রতিরোধের উপায়
Node.js এবং Express ব্যাকএন্ডে pg, mysql2, কোয়েরি বিল্ডার ও ওআরএম ব্যবহারের মাধ্যমে এসকিউএল ইনজেকশন নির্মূলের ব্যবহারিক গাইড।

বর্তমান ওয়েব ডেভেলপমেন্টে Node.js এবং Express বহুল ব্যবহৃত ফ্রেমওয়ার্ক। Express নিজে কোনো নির্দিষ্ট ডাটাবেস ড্রাইভার চাপিয়ে দেয় না বলে ডেভেলপাররা সরাসরি pg (PostgreSQL) বা mysql2 এর মতো লাইব্রেরি দিয়ে ডাটাবেস কোয়েরি লিখে থাকেন। তবে যথাযথ সচেতনতা না থাকলে স্ট্রিং কনক্যাটেনেশন বা টেমপ্লেট লিটারেলের মাধ্যমে মারাত্মক এসকিউএল ইনজেকশন দুর্বলতা তৈরি হতে পারে।
এসকিউএল ইনজেকশনের মূল ধারণা ও আক্রমণ পদ্ধতি বিশদ বুঝতে আমাদের এসকিউএল ইনজেকশন পরিচিতি ও প্রতিরোধ নির্দেশিকা পড়ে নিতে পারেন। এই গাইডে আমরা Node.js ও Express ইকোসিস্টেমে কীভাবে কোয়েরি সুরক্ষিত করতে হয় তা বিস্তারিত আলোচনা করব।
Express-এ কীভাবে এসকিউএল ইনজেকশন প্রবেশ করে
Express রাউটে ব্যবহারকারীর ইনপুট সাধারণত req.body, req.query কিংবা req.params এর মাধ্যমে আসে। যখন ডেভেলপাররা এই ইনপুট সরাসরি এসকিউএল কোয়েরি স্ট্রিংয়ে যুক্ত করেন, তখনই সিস্টেমের নিরাপত্তা হুমকির মুখে পড়ে:
// বিপজ্জনক: ঝুঁকিপূর্ণ Express রাউট
app.post('/api/users/search', async (req, res) => {
const { username } = req.body;
// সরাসরি স্ট্রিং কনক্যাটেনেশন ব্যবহার করায় ইনজেকশন সম্ভব
const query = `SELECT id, username, email FROM users WHERE username = '${username}'`;
const result = await pool.query(query);
res.json(result.rows);
});
আক্রমণকারী যদি ইউজারনেম হিসেবে ' OR '1'='1' -- পাঠায়, তবে ডাটাবেস সম্পূর্ণ ইউজার টেবিলের ডাটা উন্মুক্ত করে দেয়। তাছাড়া ডাটাবেসে মাল্টিপল স্টেটমেন্ট চালু থাকলে ডাটাবেস টেবিল মুছে ফেলার মতো বিপর্যয়ও ঘটতে পারে।
node-postgres (pg) দিয়ে PostgreSQL সুরক্ষা
node-postgres ড্রাইভার স্বয়ংক্রিয়ভাবে প্যারামিটারাইজড কোয়েরি সমর্থন করে। এখানে কোয়েরি টেক্সটে পজিশনাল প্লেসহোল্ডার ($1, $2, ইত্যাদি) এবং আলাদা অ্যারেতে ভ্যালু পাঠাতে হয়:
// নিরাপদ: pg ড্রাইভারের সাথে প্যারামিটারাইজড কোয়েরি
import { Router } from 'express';
import pool from './db.js';
const router = Router();
router.post('/api/users/search', async (req, res, next) => {
try {
const { username } = req.body;
// $1 হলো নিরাপদ প্লেসহোল্ডার যা ইনপুটকে কেবল লিটারেল ভ্যালু হিসেবে দেখে
const text = 'SELECT id, username, email FROM users WHERE username = $1 AND active = true';
const values = [username];
const { rows } = await pool.query(text, values);
res.json(rows);
} catch (err) {
next(err);
}
});
export default router;
ডায়নামিক ফিল্টারিংয়ের নিরাপদ পদ্ধতি
অপশনাল ফিল্টার বা সার্চ কোয়েরি তৈরির ক্ষেত্রেও স্ট্রিং জোড়া লাগানো যাবে না; প্যারামিটার ইনডেক্স ট্র্যাক করে কোয়েরি তৈরি করতে হবে:
// নিরাপদ: মাল্টিপল ফিল্টার বিল্ডার
export async function searchProducts({ category, minPrice, maxPrice }) {
const conditions = [];
const values = [];
if (category) {
values.push(category);
conditions.push(`category = $${values.length}`);
}
if (typeof minPrice === 'number') {
values.push(minPrice);
conditions.push(`price >= $${values.length}`);
}
if (typeof maxPrice === 'number') {
values.push(maxPrice);
conditions.push(`price <= $${values.length}`);
}
const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : '';
const text = `SELECT id, name, price, category FROM products ${whereClause} ORDER BY id DESC LIMIT 50`;
return pool.query(text, values);
}
mysql2 দিয়ে MySQL সুরক্ষা
mysql2 ড্রাইভার বাইনারি প্রিপেয়ার্ড স্টেটমেন্ট সমর্থন করে। এজন্য connection.query() এর পরিবর্তে connection.execute() ব্যবহার করতে হবে:
// নিরাপদ: mysql2-এ বাইনারি প্রিপেয়ার্ড স্টেটমেন্ট
import mysql from 'mysql2/promise';
const pool = mysql.createPool({
host: process.env.DB_HOST,
user: process.env.DB_USER,
database: process.env.DB_NAME,
password: process.env.DB_PASSWORD,
waitForConnections: true,
connectionLimit: 10
});
export async function getUserById(userId) {
// execute() ব্যবহারের মাধ্যমে ট্রু প্রিপেয়ার্ড স্টেটমেন্ট নিশ্চিত করা হয়
const sql = 'SELECT id, username, email FROM users WHERE id = ? AND deleted_at IS NULL';
const [rows] = await pool.execute(sql, [userId]);
return rows[0] || null;
}
[!IMPORTANT]
mysql2-এ সবসময়pool.query()এর পরিবর্তেpool.execute()ব্যবহার করা উচিত।execute()মেথড মাইএসকিউএল বাইনারি প্রোটোকল ব্যবহার করে স্টেটমেন্ট ক্যাশ করে, যা অ্যাপ্লিকেশনের স্পিড বাড়ায় এবং ইনজেকশন সম্পূর্ণ প্রতিরোধ করে।
কোয়েরি বিল্ডার ও ওআরএম: Knex এবং Prisma
আধুনিক ওআরএম টুলগুলো স্বয়ংক্রিয়ভাবে প্যারামিটারাইজেশন পরিচালনা করে। তবে র কোয়েরি লেখার সময় সাবধান থাকতে হবে।
নিরাপদ Knex.js ব্যবহার
import knex from 'knex';
const db = knex({ client: 'pg', connection: process.env.DATABASE_URL });
// নিরাপদ: Knex-এর নিজস্ব কোয়েরি বিল্ডার মেথড
const users = await db('users')
.select('id', 'username', 'email')
.where('status', '=', req.query.status)
.whereILike('username', `%${req.query.search}%`);
// বিপজ্জনক: knex.raw-এ স্ট্রিং ইন্টারপোলেশন (কখনই করবেন না)
// db.raw(`SELECT * FROM users WHERE status = '${req.query.status}'`);
// নিরাপদ: knex.raw-এ প্যারামিটার বাইন্ডিং
const secureRaw = await db.raw(
'SELECT * FROM users WHERE status = :status AND score > :score',
{ status: req.query.status, score: 50 }
);
Prisma ORM সেরা অভ্যাস
Prisma ক্লায়েন্ট মেথডগুলো ডিফল্টভাবেই প্যারামিটারাইজড কোয়েরি এক্সিকিউট করে:
// নিরাপদ: Prisma ক্লায়েন্ট মেথড
const user = await prisma.user.findFirst({
where: {
email: req.body.email,
isActive: true
}
});
// নিরাপদ: Prisma $queryRaw ট্যাগড টেমপ্লেট লিটারেল
// Prisma স্বয়ংক্রিয়ভাবে টেমপ্লেট ভ্যারিয়েবলগুলোকে প্যারামিটার হিসেবে বাইন্ড করে
const results = await prisma.$queryRaw`
SELECT id, email, created_at
FROM users
WHERE email = ${req.body.email}
`;
// বিপজ্জনক: $queryRawUnsafe ব্যবহার করলে প্যারামিটারাইজেশন বন্ধ হয়ে যায়
// await prisma.$queryRawUnsafe(`SELECT * FROM users WHERE email = '${email}'`); // পরিহার করুন
ব্যাকএন্ড আর্কিটেকচারে ডাটাবেস সিকিউরিটির পাশাপাশি টোকেন ভ্যালিডেশন নিশ্চিত করতে আমাদের JWT সিকিউরিটির ভুলসমূহ গাইড পড়ে দেখতে পারেন।
সচরাচর যেসব ভুল ডেভেলপাররা করে থাকেন
| ভুল পদ্ধতি | কারণ | নিরাপদ সমাধান |
|---|---|---|
| ডায়নামিক কলাম বা টেবিল নেম ইনজেকশন | প্রিপেয়ার্ড স্টেটমেন্ট শুধু ভ্যালু স্যানিটাইজ করে, আইডেন্টিফায়ার নয় | অনুমোদিত কলাম ও টেবিলের সুস্পষ্ট হোয়াইটলিস্ট (Set) ব্যবহার করুন |
IN ক্লজ স্ট্রিং জোড়া দেওয়া |
অ্যারে ভ্যালু পাস করার জটিলতা এড়াতে স্ট্রিং বানানো | পোস্টগ্রেসে WHERE id = ANY($1::int[]) ব্যবহার করুন |
| কাস্টম রেজেক্স দিয়ে স্ট্রিং এস্কেপ | নিজস্ব ফিল্টারিং ফাংশনের ওপর অতিরিক্ত নির্ভরতা | ডাটাবেস ড্রাইভারের নিজস্ব প্যারামিটারাইজড স্টেটমেন্ট ব্যবহার করুন |
| র কোয়েরিতে প্যারামিটারাইজেশন এড়িয়ে যাওয়া | জটিল কোয়েরি দ্রুত লিখতে টেমপ্লেট স্ট্রিং ব্যবহার | সর্বদা অবজেক্ট বা অ্যারে বাইন্ডিং সিনট্যাক্স ব্যবহার করুন |
| Express রেসপন্সে ডাটাবেস এরর দেখানো | ট্রাই-ক্যাচে হ্যান্ডল না করে এরর সরাসরি ক্লায়েন্টে পাঠানো | সেন্ট্রালাইজড এরর হ্যান্ডলার ব্যবহার করে জেনেরিক মেসেজ দিন |
ডায়নামিক সর্টিং কলাম হ্যান্ডলিংয়ের নিয়ম
ডাটাবেস ড্রাইভার কলাম নেম বা ASC/DESC কি-ওয়ার্ডকে কুয়েরি প্যারামিটার হিসেবে গ্রহণ করে না। তাই এগুলোকে জাভাস্ক্রিপ্ট হোয়াইটলিস্ট দিয়ে ভ্যালিডেট করতে হবে:
// নিরাপদ: হোয়াইটলিস্টেড সর্টিং লজিক
const ALLOWED_SORT_COLUMNS = new Set(['created_at', 'username', 'email', 'id']);
const ALLOWED_DIRECTIONS = new Set(['ASC', 'DESC']);
export async function getSortedUsers(sortBy = 'created_at', direction = 'DESC') {
const column = ALLOWED_SORT_COLUMNS.has(sortBy) ? sortBy : 'created_at';
const order = ALLOWED_DIRECTIONS.has(direction.toUpperCase()) ? direction.toUpperCase() : 'DESC';
const sql = `SELECT id, username, email FROM users ORDER BY ${column} ${order} LIMIT 100`;
const { rows } = await pool.query(sql);
return rows;
}
টিম কোডবেসের মান দীর্ঘমেয়াদে বজায় রাখতে ক্লিন কোড ও কোড রিভিউ নীতিমালা অনুসরণ করুন।
প্রোডাকশন ডিপ্লয়মেন্ট চেকলিস্ট
Node.js সার্ভিস প্রোডাকশনে দেওয়ার আগে নিচের বিষয়গুলো যাচাই করুন:
- প্রতিটি ডাটাবেস কলে প্যারামিটারাইজড কুয়েরি (
$1,?) বা ওআরএম এবস্ট্রাকশন ব্যবহার করা হয়েছে। - টেবিল ও সর্ট কলামের নাম কঠোর হোয়াইটলিস্টের বিপরীতে যাচাই করা হচ্ছে।
- ডাটাবেস ইউজারের কাছে কোনো স্কিমা পরিবর্তনের ক্ষমতা (DROP/ALTER) নেই।
- গ্লোবাল এরর হ্যান্ডলারে কোনো এসকিউএল এরর বা স্ট্যাক ট্রেস ক্লায়েন্টের কাছে প্রকাশ পাচ্ছে না।
- সিআই/সিডি পাইপলাইনে স্ট্যাটিক কোড অ্যানালাইসিস টুল কনফিগার করা হয়েছে।
সারসংক্ষেপ
Node.js এবং Express অ্যাপ্লিকেশনে এসকিউএল ইনজেকশন প্রতিরোধ করা সহজ। node-postgres এবং mysql2-এর নেটিভ প্যারামিটারাইজড কোয়েরি, আধুনিক ওআরএম-এর সক্ষমতা এবং আইডেন্টিফায়ারের জন্য হোয়াইটলিস্ট নীতি অনুসরণ করলে কোডবেস থেকে এসকিউএল ইনজেকশনের ঝুঁকি চিরতরে মুছে ফেলা সম্ভব।
তথ্যসূত্র: Node-Postgres Documentation on Parameterized Queries, MySQL2 Execution Protocol Specification, OWASP Node.js Security Best Practices, CWE-89 (মূল্যায়ন নভেম্বর ২০২৬)।


