استفاده از JWT در Node.js
JSON Web Token (JWT) قالبی سبک برای انتقال امن اطلاعات بین سرویسها است که در بسیاری از پروژههای Node.js برای احراز هویت و مجوزدهی (authentication & authorization) استفاده میشود. JWT مناسب برای معماریهای بدون حالت (stateless) و سرویسهای توزیعشده است، اما پیادهسازی صحیح آن نیازمند دقت به موارد امنیتی مثل امضای توکن، طول عمر، ذخیرهسازی و مکانیزم بازگشت یا ابطال (revocation) است.
ساختار JWT و نکات کلیدی
- Header: الگوریتم امضا (مثلاً HS256 یا RS256) و نوع توکن.
- Payload: ادعاها (claims) مانند sub، iss، exp و هر دادهی دلخواه که نیاز داریم منتقل شود.
- Signature: امضای دیجیتال که تضمین میکند توکن تغییر نکرده است.
نمونه ادعاهای استاندارد (claims)
| claim | توضیح |
|---|---|
| iss | صادرکننده توکن |
| sub | شناسۀ موضوع (معمولاً user id) |
| aud | گیرنده مجاز |
| exp | زمان انقضا (expiry) |
نمونه ساده: تولید و اعتبارسنجی JWT در Express
// Install: npm install express jsonwebtoken
const express = require('express');
const jwt = require('jsonwebtoken');
const app = express();
app.use(express.json());
const ACCESS_TOKEN_SECRET = 'your-very-secure-secret';
const ACCESS_TOKEN_EXPIRY = '15m';
app.post('/login', (req, res) => {
const { username } = req.body;
// Authenticate user (مثال ساده)
const user = { id: 1, username };
const payload = { sub: user.id, username: user.username };
const token = jwt.sign(payload, ACCESS_TOKEN_SECRET, { expiresIn: ACCESS_TOKEN_EXPIRY });
res.json({ accessToken: token });
});
function authenticateToken(req, res, next) {
const authHeader = req.headers['authorization'];
const token = authHeader && authHeader.split(' ')[1];
if (!token) return res.sendStatus(401);
jwt.verify(token, ACCESS_TOKEN_SECRET, (err, user) => {
if (err) return res.sendStatus(403);
req.user = user;
next();
});
}
app.get('/profile', authenticateToken, (req, res) => {
res.json({ message: 'Protected data', user: req.user });
});
app.listen(3000);توضیح: این کد یک اندپوینت /login ایجاد میکند که پس از احراز هویت (مثال ساده) یک توکن دسترسی ۱۵ دقیقهای با کلید متقارن تولید میکند. تابع authenticateToken هدر Authorization را خوانده و توکن را با jwt.verify بررسی میکند. اگر توکن معتبر نباشد، پاسخ 401 یا 403 باز میگردد.
بهبودها و بهترین شیوهها
- استفاده از توکنهای دسترسی کوتاهمدت و رفرش توکن برای جلسات طولانیتر.
- ذخیره رفرش توکن در پایگاه داده یا Redis برای امکان ابطال (blacklist) و گردش رفرش.
- استفاده از کوکیهای HttpOnly و Secure بهجای localStorage برای کاهش خطر XSS.
- در صورت نیاز به امنیت بیشتر، استفاده از الگوریتمهای نامتقارن (RS256) با کلید خصوصی و عمومی.
الگوی Access + Refresh Token
// Pseudocode: Access token short-lived, refresh token stored server-side
// On login:
// 1. Verify credentials
// 2. Issue accessToken (exp: 15m)
// 3. Issue refreshToken (longer) and store hash(refreshToken) in DB tied to user
// On refresh request:
// 1. Verify refreshToken exists in DB and is valid
// 2. Rotate: remove old refresh from DB, insert new refresh
// 3. Issue new accessToken and new refreshTokenتوضیح: این الگو کمک میکند اگر یک رفرش توکن لو برود، با گردش (rotation) و ذخیرهسازی سرور-طرف، بتوان دسترسی آن را قطع کرد. هر رفرش توکن معمولاً بهصورت هششده در دیتابیس ذخیره میشود تا در صورت لو رفتن دیتابیس، توکن خام در دسترس نباشد.
نمونه: استفاده از RS256 (کلید خصوصی/عمومی)
const fs = require('fs');
const jwt = require('jsonwebtoken');
const privateKey = fs.readFileSync('./private.pem', 'utf8');
const publicKey = fs.readFileSync('./public.pem', 'utf8');
const token = jwt.sign({ sub: 123 }, privateKey, { algorithm: 'RS256', expiresIn: '10m' });
jwt.verify(token, publicKey, { algorithms: ['RS256'] }, (err, payload) => {
if (err) console.error('invalid', err);
else console.log('payload', payload);
});توضیح: در این مثال از الگوریتم نامتقارن RS256 استفاده شده است. کلید خصوصی برای امضا نگه داشته میشود و کلید عمومی را میتوان در سرویسهای دیگر برای اعتبارسنجی منتشر کرد. این مهم است وقتی سرویسها یا کلاینتهای مختلف باید توکنها را اعتبارسنجی کنند بدون داشتن کلید خصوصی.
ملاحظات امنیتی و رایجترین اشتباهات
- هرگز کلید مخفی را در کد منبع عمومی قرار ندهید؛ از متغیرهای محیطی یا secret management استفاده کنید.
- از توکن طولانیمدت بدون مکانیزم ابطال استفاده نکنید.
- برای اطلاعات حساس، نباید آنها را در payload توکن قرار دهید مگر ضروری باشد؛ چرا که payload رمزنگاری نمیشود مگر از JWE استفاده کنید.
- مراقب CSRF باشید؛ در صورت ذخیره با کوکی از روشهای ضد-CSRF استفاده کنید یا توکن CSRF جداگانه ارسال کنید.
مقایسه روشهای ذخیرهسازی توکن
| محل ذخیره | مزایا | معایب |
|---|---|---|
| localStorage | ساده، دسترسی آسان از جاوااسکریپت | آسیبپذیر در برابر XSS |
| HttpOnly Cookie | محافظت از XSS، قابل استفاده برای درخواستهای خودکار | نیاز به محافظت از CSRF |
| Memory | کوتاهمدت و ایمنتر از XSS | با ریفرش صفحه از بین میرود |
نتیجهگیری و توصیههای عملی
JWT در Node.js ابزار قدرتمندی برای مدیریت احراز هویت است، بهخصوص در معماریهای میکروسرویس یا زمانی که میخواهید سرور حالتدار نباشد. اما پیادهسازی امن آن شامل انتخاب الگوریتم مناسب، مدیریت کلیدها، استفاده از توکنهای کوتاهمدت بههمراه رفرش توکنهای قابل ابطال، و انتخاب مکانیزم ذخیرهسازی امن است. پیش از استفاده از JWT، مشخص کنید که آیا نیاز به حالت بدونحالت دارید یا یک سشن سنتی امن (server-side session) برای برنامهتان مناسبتر است.
آیا این مطلب برای شما مفید بود ؟




