7 روش بهترین برای پاکسازی ورودی در Node.js
وقتی صحبت از توسعه وب میشود، به خصوص با Node.js، پاکسازی ورودی یکی از آن موضوعاتی است که کنار گذاشته میشود — تا زمانی که چیزی به شدت اشتباه پیش برود.
این را تصور کنید: شما اپلیکیشن جدید و درخشان Node.js خود را راهاندازی کردهاید، همه چیز به خوبی کار میکند… تا زمانی که با یک NoSQL injection مورد حمله قرار میگیرید یا کسی از یک تگ script برای ربودن ورودیهای فرم شما استفاده میکند. ناگهان، شما در حال تلاش برای رفع آسیبپذیریهایی هستید که حتی نمیدانستید وجود دارند.
بیایید با واقعیت روبرو شویم: اگر هر ورودی کاربری را میپذیرید — از طریق فرم، query string، درخواست API، یا حتی کوکیها — در حال بازی با آتش هستید. پاکسازی فقط یک چکباکس برای ممیزی امنیتی نیست. این بخش اصلی ساخت اپلیکیشنهای قابل اعتماد است.
1. تفاوت بین اعتبارسنجی و پاکسازی را درک کنید
قبل از شیرجه زدن به کد، باید چیزی را کاملاً روشن کنیم:
اعتبارسنجی بررسی میکند که آیا ورودی همان چیزی است که انتظار دارید.
پاکسازی ورودی را تمیز میکند تا برای پردازش یا ذخیرهسازی ایمن شود.
این یک مثال است:
// اعتبارسنجی
if (typeof userInput === 'string' && userInput.length < 50) {
// خوب است
}
// پاکسازی
const sanitizedInput = userInput.replace(/[^\w\s]/gi, '');چرا این مهم است: بسیاری از توسعهدهندگان ورودی را اعتبارسنجی میکنند و فرض میکنند که ایمن است. اما مهاجمان هنوز میتوانند کد مخرب را از طریق ورودیهایی که معتبر به نظر میرسند، مخفیانه وارد کنند. اعتبارسنجی بدون پاکسازی مانند قفل کردن درب جلو اما باز گذاشتن پنجره است.
روش بهترین: هر دو را انجام دهید. ابتدا نوع و ساختار ورودی را اعتبارسنجی کنید. سپس آن را پاکسازی کنید تا کاراکترهای ناخواسته، کد، یا بردارهای تزریق را حذف کنید.
2. از کتابخانههای قابل اعتماد مانند validator.js و DOMPurify استفاده کنید
اختراع دوباره چرخ جالب است تا زمانی که از صخره پایین بیفتید.
Node.js کتابخانههای عالیای دارد که توسط افرادی که به امنیت توجه دارند، نگهداری میشوند. در اینجا دو مورد اصلی وجود دارد:
validator.js
عالی برای اعتبارسنجی و پاکسازی رشتهها — مانند ایمیلها، URLها، ورودیهای الفبایی-عددی و بیشتر.
npm install validator
const validator = require('validator');
const email = '<script>evil()</script>user@example.com';
if (validator.isEmail(email)) {
const safeEmail = validator.normalizeEmail(email);
console.log(safeEmail); // 'user@example.com'
}DOMPurify (از طریق JSDOM در Node.js)
عمدتاً برای پاکسازی ورودیهای HTML استفاده میشود (مثلاً نظرات، محتوای WYSIWYG).
npm install dompurify jsdom
const { JSDOM } = require('jsdom');
const createDOMPurify = require('dompurify');
const window = new JSDOM('').window;
const DOMPurify = createDOMPurify(window);
const dirtyHTML = '<img src=x onerror=alert(1)>';
const cleanHTML = DOMPurify.sanitize(dirtyHTML);
console.log(cleanHTML); // <img src="x">چرا این مهم است: شما نمیتوانید هر بردار XSS یا تزریق را به صورت دستی بگیرید. از کتابخانههایی استفاده کنید که با تهدیدات جدید تکامل مییابند.
3. در برابر حملات تزریق محافظت کنید (SQL, NoSQL, Command Injection)
حملات تزریق یکی از قدیمیترین ترفندهای کتاب هستند — و هنوز هم برای ورودیهای ضعیف پاکسازی شده بسیار مؤثر هستند.
تزریق NoSQL (MongoDB)
// کد آسیبپذیر
User.find({ username: req.body.username });اگر کسی این را ارسال کند:
{ "username": { "$gt": "" } }آنها میتوانند منطق ورود را کاملاً دور بزنند.
راه حل:
از $expr و انواع صریح استفاده کنید:
const username = validator.escape(req.body.username);
User.find({ username: username });بهتر است، از اعتبارسنجی schema Mongoose استفاده کنید:
const userSchema = new mongoose.Schema({
username: { type: String, required: true, match: /^[a-zA-Z0-9]+$/ }
});تزریق دستور (Command Injection)
const { exec } = require('child_process');
exec(`ping ${req.query.host}`);یک کاربر مخرب میتواند تزریق کند:
; rm -rf /راه حل:
از spawn با آرایههای آرگومان استفاده کنید، نه string interpolation:
const { spawn } = require('child_process');
spawn('ping', [req.query.host]);چرا این مهم است: حملات تزریق میتوانند دیتابیسها را پاک کنند، نشستها را ربوده کنند، یا دسترسی غیرمجاز با تلاش بسیار کمی به دست آورند — مگر اینکه ورودی شما پاکسازی شده باشد.
4. تمام نقاط ورودی را پاکسازی کنید (نه فقط فرمها)
وسوسهانگیز است که تمام تلاشهای پاکسازی را روی ورودیهای فرم متمرکز کنیم، اما بیایید دامنه خود را گسترش دهیم.
در اینجا برخی از بردارهای حمله رایج وجود دارد:
URL query strings: /search?term=<script>
HTTP headers: User-Agent, Referer
Cookies: به خصوص آنهایی که در احراز هویت یا ردیابی استفاده میشوند
Webhooks: دادههای ورودی از سرویسهای شخص ثالث
Sockets/WebRTC: ارتباط real-time با کلاینتها
راه حل:
دادهها را قبل از استفاده در موارد زیر نرمالسازی و پاکسازی کنید:
مسیرهای فایل
Queryها
Templateها
JSON payloadها
لاگها
مثال:
const term = validator.escape(req.query.term || '');
console.log('Search term:', term);حتی هنگام لاگکردن یا نمایش دادهها به کاربران، آن را پاکسازی کنید. XSS میتواند حتی از طریق لاگها در برخی پنلهای مدیریتی رخ دهد.
5. طول و نوع ورودی را محدود کنید
شما تعجب میکنید که چقدر اغلب باگها و سوءاستفادهها از ورودی نامحدود ناشی میشوند.
تصور کنید یک ورودی bio را میپذیرید و کسی یک رشته 10 مگابایتی ارسال میکند. یا یک نام کاربری به عنوان یک object. حالا اپلیکیشن شما متوقف میشود، دیتابیس شما گریه میکند، و مهاجمان لبخند میزنند.
راه حل:
از محدودیتها در همه جا استفاده کنید — در middleware، schemaها، و فرمهای frontend.
مثال Express Middleware
app.use(express.json({ limit: '1kb' }));مثال Mongoose Schema
const commentSchema = new mongoose.Schema({
body: {
type: String,
maxlength: 500,
required: true
}
});اعتبارسنجی Joi Schema
const Joi = require('joi');
const schema = Joi.object({
username: Joi.string().alphanum().min(3).max(30).required()
});چرا این مهم است: این ریاضی ساده است. داده کمتر = فرصت کمتر برای سوءاستفاده.
6. خروجی را Escape کنید تا از XSS جلوگیری شود
گاهی اوقات پاکسازی ورودی کافی نیست. شما همچنین باید خروجی را escape کنید، به خصوص هنگام رندر کردن محتوای پویا.
مثال از روش بد (رندر کردن ورودی کاربر):
<div>${userComment}</div>اگر کسی این را وارد کند:
<script>alert('XSS')</script>در مرورگر اجرا میشود.
راه حل:
از یک کتابخانه escape خروجی یا پاکسازی template داخلی استفاده کنید.
با EJS:
<%= userComment %> <!-- به صورت پیشفرض escape میکند -->با Handlebars:
{{userComment}} <!-- به صورت پیشفرض escape میکند -->از تگهای unescaped مانند <%- userComment %> اجتناب کنید مگر اینکه 100% مطمئن باشید ورودی پاکسازی شده است (مثلاً با استفاده از DOMPurify).
چرا این مهم است: XSS میتواند همه چیز را از سرقت کوکی تا تغییر ظاهر UI و فیشینگ انجام دهد. Escape کردن خروجی دیوار نهایی دفاع شما است.
7. پاکسازی ورودی را با Middleware خودکار کنید
پاکسازی دستی هر فیلد ورودی در هر route؟ این درخواست برای باگ است. در عوض، middlewareای ایجاد کنید که ورودی را به صورت مرکزی رهگیری و تمیز میکند.
مثال: Middleware پاکسازی بازگشتی
const sanitize = require('sanitize-html');
function sanitizeBody(req, res, next) {
function deepSanitize(obj) {
for (let key in obj) {
if (typeof obj[key] === 'string') {
obj[key] = sanitize(obj[key]);
} else if (typeof obj[key] === 'object') {
deepSanitize(obj[key]);
}
}
}
if (req.body) deepSanitize(req.body);
if (req.query) deepSanitize(req.query);
next();
}
app.use(sanitizeBody);میتوانید کتابخانههایی مانند xss-filters، validator، یا sanitize-html را بسته به نیاز خود وصل کنید.
چرا این مهم است: پاکسازی متمرکز خطای انسانی را کاهش میدهد. اگر منطق انتزاعی شده و در routeها استفاده مجدد شود، یک فیلد را از دست نمیدهید.
نکات اضافی: موارد لبه دنیای واقعی که باید مراقب آنها باشید
حملات Whitespace: کاراکترهای مخفی مانند \u200B (فضای بدون عرض) میتوانند از regexها عبور کنند.
سوءاستفاده Unicode: دامنههای Punycode و emoji میتوانند کاربران را فریب دهند (حملات xn--).
JSON تو در تو: مهاجمان میتوانند payloadها را 10 سطح عمیق دفن کنند. همیشه عمق را نرمالسازی کنید.
Regex Denial of Service (ReDoS): الگوهای بیش از حد پیچیده میتوانند اپلیکیشن شما را خراب کنند. regexهای خود را تست کنید.
آپلود فایل: همیشه نام فایلها را پاکسازی کنید و از کتابخانههایی مانند multer برای محدود کردن اندازه و انواع MIME استفاده کنید.
نتیجهگیری
پاکسازی ورودی در Node.js فقط در مورد اجتناب از باگ نیست — این در مورد ساخت اپلیکیشنهایی است که مردم میتوانند به آنها اعتماد کنند. ما از عصر "سریع حرکت کنید و چیزها را بشکنید" گذشتهایم. حالا این "سریع حرکت کنید و رمزهای عبور را نشت ندهید یا دیتابیس خود را نابود نکنید" است.
در اینجا چکلیست سریع شما برای مدیریت ایمن ورودی در Node.js است:
→ انواع و فرمتها را اعتبارسنجی کنید
→ با استفاده از کتابخانههای قابل اعتماد پاکسازی کنید
→ خروجی را در templateها escape کنید
→ طولها و عمقها را محدود کنید
→ از تزریق جلوگیری کنید
→ تمیز کردن ورودی را متمرکز کنید
→ موارد لبه را تست کنید
امنیت هرگز یک کار یکباره نیست — اما این روشها اپلیکیشن Node.js شما را در زمین محکم نگه میدارند.





