ویژگی تصویر

جلوگیری از حملات XSS و CSRF در Node.js

  /  Node.js   /  جلوگیری از حملات XSS و CSRF در Node.js
بنر تبلیغاتی الف
NodeJS - Node.js

حملات XSS (Cross‑Site Scripting) و CSRF (Cross‑Site Request Forgery) از شایع‌ترین تهدیدها برای برنامه‌های وب هستند. در محیط Node.js و به‌ویژه با فریم‌ورک‌هایی مانند Express، آگاهی از روش‌های پیشگیری و پیاده‌سازی مکانیزم‌های حفاظتی ضروری است. این مقاله راهکارهای عملی، نمونه‌های کد و نکات تخصصی برای جلوگیری از XSS و CSRF در Node.js را پوشش می‌دهد.

درک اولیه: XSS و CSRF

  • XSS: حمله‌ای که در آن مهاجم کد جاوااسکریپت مخرب را به صفحهٔ وب تزریق می‌کند و در زمینهٔ اعتبار کاربر اجرا می‌شود. شامل نسخه‌های Reflected، Stored و DOM‑based است.
  • CSRF: حمله‌ای که در آن درخواست‌های معتبر از طرف کاربر (معمولاً از طریق کوکی‌های احراز هویت) بدون رضایت او به سرور ارسال می‌شود.

اصول کلی جلوگیری

  • ورودی‌ها را همیشه اعتبارسنجی و پاکسازی (sanitize) کنید.
  • خروجی را همیشه Escape کنید — مخصوصاً هنگام رندر HTML.
  • از هدرهای امنیتی (CSP، X‑Content‑Type‑Options و غیره) استفاده کنید.
  • برای درخواست‌های state‑changing از توکن‌های CSRF یا مکانیزم‌های معادل استفاده کنید و کوکی‌ها را با پرچم‌های مناسب تنظیم کنید.

جلوگیری از XSS در Node.js

۱) پاکسازی و فیلتر ورودی

const sanitizeHtml = require('sanitize-html');

const clean = sanitizeHtml(userInput, {
  allowedTags: ['b', 'i', 'em', 'strong', 'a'],
  allowedAttributes: { 'a': ['href'] }
});

توضیح: کد بالا با استفاده از بسته sanitize-html ورودی کاربر را پاکسازی می‌کند و فقط تگ‌ها/اتریبیوت‌های مجاز را نگه می‌دارد. این مناسب برای مواردی است که به کاربر اجازهٔ محدود نوشتن HTML می‌دهید.

۲) استفاده از قالب‌بندی (templating) امن

بیشتر موتورهای template مانند Pug، EJS یا Handlebars به‌صورت پیش‌فرض خروجی را Escape می‌کنند. هنگام استفاده از raw HTML مراقب باشید و تنها زمانی آن را رندر کنید که به‌خوبی پاکسازی شده باشد.

۳) جلوگیری از DOM‑based XSS

// آسیب‌پذیر: استفاده از innerHTML با دادهٔ نا‌مطمئن
element.innerHTML = location.hash;

// امن: استفاده از textContent
element.textContent = location.hash;

توضیح: در کد اول دادهٔ URL مستقیماً به innerHTML تزریق شده که منجر به اجرای اسکریپت می‌شود. در نسخه امن از textContent استفاده شده که متن را بدون تفسیر HTML قرار می‌دهد.

۴) سیاست محتوایی (CSP)

const helmet = require('helmet');

app.use(helmet.contentSecurityPolicy({
  directives: {
    defaultSrc: ["'self'"],
    scriptSrc: ["'self'", "https://trusted-scripts.example.com"],
    objectSrc: ["'none'"],
    upgradeInsecureRequests: []
  }
}));

توضیح: این تنظیمات با کمک helmet هدر CSP را اضافه می‌کند تا بارگذاری اسکریپت‌ها و منابع فقط از منابع مشخص مجاز باشد و از اجرای اسکریپت‌های درون‌خطی جلوگیری کمک می‌کند.

جلوگیری از CSRF در Node.js

۱) الگوهای رایج و توصیه‌شده

  • Synchronizer Token Pattern: سرور توکن تصادفی تولید و در فرم‌ها یا هدرها قرار می‌دهد و سرور آن را اعتبارسنجی می‌کند.
  • Double Submit Cookie: توکن در کوکی و به عنوان پارامتر یا هدر ارسال می‌شود و باید برابر باشند.
  • استفاده از SameSite cookies: پرچم SameSite=Lax/Strict می‌تواند بسیاری از حملات CSRF را مسدود کند.

۲) استفاده از middleware ایمن در Express

const express = require('express');
const cookieParser = require('cookie-parser');
const csurf = require('csurf');

const app = express();
app.use(cookieParser());
app.use(express.urlencoded({ extended: true }));

// استفاده از csurf با ذخیره‌سازی در کوکی
app.use(csurf({ cookie: { httpOnly: true, sameSite: 'lax', secure: true } }));

app.get('/form', (req, res) => {
  res.send(`<button type="submit">Send</button>`);
});

app.post('/process', (req, res) => {
  res.send('Form processed');
});

توضیح: این مثال با csurf توکن CSRF تولید کرده و آن را در فرم مخفی قرار می‌دهد. middleware کوکی با پرچم‌های HttpOnly، SameSite و Secure تنظیم شده است تا ایمنی بیشتری فراهم کند.

۳) APIها و SPAها

برای APIهای REST یا SPA بهتر است از توکن‌های احراز هویت در هدر Authorization (مانند JWT) استفاده کنید و CORS را به‌درستی پیکربندی کنید. استفاده از کوکی‌های احراز هویت همراه با CSRF token یا SameSite مناسب است.

تنظیم کوکی‌ها و هدرها (جدول سریع)

پرچمتوضیح
HttpOnlyدسترسی جاوااسکریپت به کوکی را مسدود می‌کند (کاهش XSS→سرقت کوکی).
Secureکوکی فقط از طریق HTTPS ارسال می‌شود.
SameSite=Lax/Strictتعیین می‌کند آیا کوکی‌ها در درخواست‌های کراس‌سایت ارسال شوند (کاهش CSRF).

نکات تخصصی و عملیاتی

  • همیشه لایه‌ها را ترکیب کنید: پاکسازی ورودی + خروجی Escape + هدرهای امنیتی + تنظیم کوکی.
  • برای برنامه‌های با کاربران واردشده، توکن‌های CSRF را برای عملیات state‑changing (POST/PUT/DELETE) اجباری کنید.
  • مراقب CORS باشید: اجازه دادن به Origin: * برای منابع حساس خطرناک است.
  • برای SPA که از JWT استفاده می‌کنند، توصیه می‌شود توکن‌ها در حافظه یا storage امن نگهداری شده و درخواست‌ها با هدر Authorization ارسال شوند تا نیاز به کوکی نباشد؛ در این حالت CSRF کمتر مسئله‌ساز خواهد بود زیرا حمله‌کننده نمی‌تواند header Authorization را از دامنهٔ دیگر تنظیم کند.
  • محدودسازی طول و نوع ورودی‌ها (whitelisting) بهتر از blacklist است.

نمونه آسیب‌پذیر و اصلاح‌شده: ارسال پیام کاربر

// آسیب‌پذیر: ذخیرهٔ متن بدون پاکسازی و سپس رندر
app.post('/comment', (req, res) => {
  db.save({ text: req.body.text });
  res.redirect('/comments');
});

// رندر در template:
<div class="comment"></div>

توضیح: اگر template Escape را غیرفعال کند یا متن بدون پاکسازی ذخیره شود، ممکن است XSS Stored رخ دهد.

// اصلاح: پاکسازی قبل از ذخیره و اطمینان از Escape در template
const sanitizeHtml = require('sanitize-html');

app.post('/comment', (req, res) => {
  const clean = sanitizeHtml(req.body.text, { allowedTags: [], allowedAttributes: {} });
  db.save({ text: clean });
  res.redirect('/comments');
});

توضیح: در نسخهٔ اصلاح‌شده متن قبل از ذخیره پاکسازی می‌شود و template هم باید خروجی را Escape کند. این ترکیب از XSS ذخیره‌شده جلوگیری می‌کند.

جمع‌بندی

پیشگیری از XSS و CSRF در Node.js نیازمند ترکیب چند تکنیک است: پاکسازی و Escape، هدرهای امنیتی مانند CSP، پیکربندی صحیح کوکی‌ها و استفاده از توکن‌های CSRF یا مکانیزم‌های مناسب برای APIها. بررسی مداوم وابستگی‌ها، آزمون‌های نفوذ و تحلیل محتوای خروجی به کاهش سطح حمله کمک می‌کند.

منابع عملی: از پکیج‌هایی مانند helmet، csurf، sanitize-html و استفاده از اصول امن‌نویسی در سمت کلاینت (textContent به جای innerHTML) بهره ببرید. در نهایت، پیاده‌سازی چند لایهٔ امنیتی همیشه بهتر از تکیه بر یک مکانیزم منفرد است.

آیا این مطلب برای شما مفید بود ؟

خیر
بله
موضوعات شما در انجمن: