ویژگی تصویر

امنیت در برنامه‌های Node.js — راهنمای عملی و کاربردی

  /  Node.js   /  امنیت در برنامه های Node.js
بنر تبلیغاتی الف
NodeJS - Node.js

با گسترش استفاده از Node.js در پروژه‌های وب و سرویس‌های میکروسرویسی، مباحث امنیتی اهمیت زیادی پیدا کرده‌اند. این مقاله به طور جامع و کاربردی نکات کلیدی و تکنیک‌های محافظتی برای افزایش امنیت برنامه‌های Node.js را پوشش می‌دهد؛ از تنظیمات سرور و مدیریت وابستگی‌ها گرفته تا محافظت از احراز هویت و جلوگیری از حملات معمول.

تهدیدهای رایج در برنامه‌های Node.js

  • تزریق (SQL/NoSQL Injection)
  • Cross-Site Scripting (XSS) و Cross-Site Request Forgery (CSRF)
  • لو رفتن توکن‌ها یا کلیدها (Secrets Leakage)
  • حملات DOS/Brute Force
  • وابستگی‌های آسیب‌پذیر در npm
  • Session hijacking و سوء‌استفاده از کوکی‌ها

اصول اولیه امنیت و پیکربندی سرور

قبل از هر چیز باید محیط اجرا (runtime) و زیرساخت را امن کنید: از HTTPS استفاده کنید، TLS را درست پیکربندی کنید، پورت‌های غیرضروری را ببندید و به‌روزرسانی‌های سیستم و کتابخانه‌ها را مرتب اعمال کنید.

نمونه: راه‌اندازی HTTPS در Node.js

const fs = require('fs');
const https = require('https');
const express = require('express');

const app = express();
app.get('/', (req, res) => res.send('Hello secure world'));

const options = {
  key: fs.readFileSync('/path/to/privkey.pem'),
  cert: fs.readFileSync('/path/to/fullchain.pem')
};

https.createServer(options, app).listen(443, () => {
  console.log('HTTPS server running on port 443');
});

توضیح: این کد یک سرور HTTPS ساده با Express ایجاد می‌کند. استفاده از گواهی معتبر (مثلاً از Let’s Encrypt) و خواندن فایل‌های کلید/گواهی از مسیر امن ضروری است. در محیط تولید هرگز کلیدها را در مخزن گیت ذخیره نکنید؛ از secret manager یا سرویس‌هایی مثل AWS Secrets Manager / Azure Key Vault استفاده کنید.

محافظت لایه کاربردی: هِلمِت، CORS و هِدِرها

کتابخانه Helmet برای تنظیم هدرهای امنیتی مفید است. همچنین CORS را به دقت پیکربندی کنید تا فقط دامنه‌های مورد اعتماد اجازه دسترسی داشته باشند.

const helmet = require('helmet');
const cors = require('cors');

app.use(helmet());
app.use(cors({
  origin: ['https://yourdomain.com'],
  methods: ['GET', 'POST'],
  credentials: true
}));

توضیح: helmet هدرهایی مثل X-Frame-Options، X-Content-Type-Options و Content-Security-Policy را تنظیم می‌کند. CORS نیز دسترسی منابع را محدود می‌کند. توجه داشته باشید که استفاده از origin: ‘*’ همراه با credentials کار نمی‌کند و خطرناک است.

احراز هویت و مدیریت نشست (Sessions)

برای ذخیره نشست‌ها از کوکی‌های امن یا توکن‌های کوتاه‌مدت استفاده کنید. در صورت استفاده از JWT، نکات زیر را رعایت کنید:

  • از امضای قوی (RS256 یا HS256 با کلید قوی) استفاده کنید.
  • زمان عمر (exp) کوتاه و مکان برای ریفرش توکن در نظر بگیرید.
  • توکن‌های حساس را در کوکی‌های HttpOnly و Secure ذخیره کنید تا دسترسی جاوااسکریپت به آن‌ها محدود شود.
const jwt = require('jsonwebtoken');

const token = jwt.sign({ userId: 123 }, process.env.JWT_SECRET, {
  algorithm: 'HS256',
  expiresIn: '15m'
});

توضیح: ساخت JWT با کلید مخفی و زمان انقضای کوتاه. در محیط تولید از کلیدهای قوی استفاده کنید و آن‌ها را در متغیرهای محیطی نگهدارید. برای refresh token از مکانیزم امن و با امکان لغو (revocation) استفاده کنید.

حفظ امنیت ورودی‌ها و جلوگیری از تزریق

هر ورودی کاربر باید اعتبارسنجی و سودمندی آن کنترل شود. برای SQL از پرس‌وجوهای پارامتری یا ORMهای امن استفاده کنید. برای NoSQL مثل MongoDB مراقب prototype pollution و عملیات‌هایی که ورودی مستقیم را اجرا می‌کنند باشید.

// نمونه استفاده از pg با پارامترها (Postgres)
const { Pool } = require('pg');
const pool = new Pool();

const getUserByEmail = async (email) => {
  const res = await pool.query('SELECT * FROM users WHERE email = $1', [email]);
  return res.rows[0];
};

توضیح: استفاده از پارامترها (در اینجا $1) جلوی SQL injection را می‌گیرد. هرگز ورودی‌ها را با concat مستقیم در کوئری قرار ندهید.

رمزنگاری رمزعبورها و داده‌های حساس

برای ذخیره رمزعبورها از الگوریتم‌های قوی مانند bcrypt یا Argon2 استفاده کنید. هرگز از هش‌های ساده یا مقایسه متنی استفاده نکنید.

const bcrypt = require('bcrypt');

async function hashPassword(plain) {
  const saltRounds = 12;
  const hash = await bcrypt.hash(plain, saltRounds);
  return hash;
}

async function verifyPassword(plain, hash) {
  return await bcrypt.compare(plain, hash);
}

توضیح: bcrypt با salt داخلی کار می‌کند و مقدار saltRounds را متناسب با قدرت سخت‌افزار تنظیم کنید (افزایش rounds کندتر اما امن‌تر است). در مقابل Argon2 عملکرد امنیتی بهتری دارد و در پروژه‌های جدید پیشنهاد می‌شود.

محافظت در برابر حملات DoS و Brute-Force

  • Rate limiting برای نقاط حساس مثل login ایجاد کنید (express-rate-limit).
  • Captcha برای فرم‌های ورود یا ثبت‌نام اضافه کنید.
  • مانیتورینگ و alert برای افزایش ناگهانی ترافیک تنظیم کنید.
const rateLimit = require('express-rate-limit');

app.use('/api/', rateLimit({
  windowMs: 15 * 60 * 1000, // 15 minutes
  max: 100, // limit each IP to 100 requests per windowMs
  standardHeaders: true,
  legacyHeaders: false
}));

توضیح: این مثال محدودیت درخواست را در مسیرهای API اعمال می‌کند تا حملات تکراری کنترل شوند. برای مسیرهای حساس مانند /login تنظیمات سخت‌گیرانه‌تری اعمال کنید.

مدیریت وابستگی‌ها و اسکن آسیب‌پذیری

وابستگی‌های npm را مرتباً با ابزارهایی مثل npm audit، Snyk یا Dependabot بررسی و به‌روز کنید. در CI pipelines، اسکن خودکار آسیب‌پذیری‌ها را قرار دهید و قوانین شکست‌خورده (fail build) در صورت وجود آسیب‌پذیری‌های بحرانی اعمال کنید.

نمونه جدول ابزارها و کارکرد

ابزارکارکرد
helmetتنظیم هدرهای امنیتی
express-rate-limitمحدودسازی درخواست‌ها
npm audit / Snykاسکن وابستگی‌ها برای آسیب‌پذیری
OWASP ZAPاسکن امنیتی خودکار برنامه وب

بهترین شیوه‌های عملی و نکات پایانی

  • هرگز secrets (کلیدها، پسوردها) را در کد منبع قرار ندهید؛ از secret manager استفاده کنید.
  • ورود به سیستم و لاگینگ را طوری انجام دهید که داده‌های حساس لاگ نشوند.
  • پالیسی‌های CSP را برای جلوگیری از XSS پیاده کنید.
  • دسترسی به دیتابیس و سرویس‌ها را با حداقل امتیازات (least privilege) پیکربندی کنید.
  • تست نفوذ (pentest) و اسکن امنیتی منظم را فراموش نکنید.

مثال: فعال کردن Content Security Policy با Helmet

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

توضیح: CSP با تعیین منابع مجاز برای اسکریپت‌ها، استایل‌ها و رسانه‌ها از XSS محافظت می‌کند. در محیطی که از CDN استفاده می‌کنید، دامنه‌های امن را داخل policy قرار دهید و قبل از اعمال در سطح تولید، سیاست را در حالت گزارش‌گیری (report-only) بررسی کنید.

جمع‌بندی: امنیت در Node.js ترکیبی از پیکربندی درست سرور، محافظت در لایهٔ کاربرد، اعتبارسنجی ورودی، مدیریت امن توکن‌ها و کنترل وابستگی‌ها است. رعایت این نکات به همراه مانیتورینگ و اسکن مداوم می‌تواند خطرات رایج را به طور قابل‌توجهی کاهش دهد.

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

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