توکنهای وب JSON (JWT) به استاندارد پیشفرض برای احراز هویت بدون حالت در برنامههای وب مدرن تبدیل شدهاند. آنها به سرورها اجازه میدهند هویت کاربر را بدون پرسوجو از پایگاه داده برای هر درخواست تأیید کنند. با این حال، راحتی آنها اغلب منجر به پیکربندی نادرست شده و برنامهها را در معرض آسیبپذیریهای جدی امنیتی قرار میدهد. در این راهنما، ما استراتژیهای پیشرفتهای را برای سختتر کردن پیادهسازی JWT خود بررسی میکنیم و از سینتکس پایه فراتر رفته و به معماری امنیتی قوی میپردازیم.
1. انتخاب الگوریتمها و کلیدهای قوی
یکی از حیاتیترین نقصهای امنیتی در پیادهسازی JWT، انتخاب نادرست الگوریتمهای امضا است. بسیاری از آموزشها به سادگی HS256 را توصیه میکنند که به یک کلید متقارن متکی است. اگرچه این روش برای خدمات داخلی مناسب است، اما در سیستمهای توزیعشده که کلید محرمانه باید بین خدمات به اشتراک گذاشته شود، خطراتی ایجاد میکند. در عوض، الگوریتمهای نامتقارن مانند RS256 یا ES256 را ترجیح دهید. این الگوریتمها به شما امکان میدهند یک کلید عمومی برای تأیید منتشر کنید در حالی که کلید خصوصی را به صورت ایمن روی سرور نگه میدارید.
علاوه بر این، هرگز از رمزهای ضعیف یا خالی استفاده نکنید. همیشه از رشتههای تصادفی با آنتروپی بالا که توسط یک تولیدکننده عدد تصادفی رمزنگاریای امن ایجاد شدهاند، استفاده کنید. در زیر نمونهای از تولید یک کلید خصوصی امن برای RS256 در Node.js آورده شده است:
const crypto = require('crypto');
// Generate a 2048-bit RSA key pair
const { publicKey, privateKey } = crypto.generateKeyPairSync('rsa', {
modulusLength: 2048,
publicKeyEncoding: {
type: 'spki',
format: 'pem'
},
privateKeyEncoding: {
type: 'pkcs8',
format: 'pem'
}
});
console.log(privateKey); // Store this securely, e.g., in a vault
console.log(publicKey); // Distribute this to clients for verification
2. اجبار زمان انقضای کوتاه
JWTها باید عمر کوتاهی داشته باشند. یک توکن با پنجره انقضای طولانی (مثلاً 24 ساعت یا 30 روز) پنجره خطر را در صورت سرقت توکن افزایش میدهد. بهترین شیوه این است که توکنهای دسترسی (Access Tokens) با عمر کوتاه (15 تا 30 دقیقه) صادر شوند و از توکنهای تازهسازی (Refresh Tokens) برای جلسات بلندمدت استفاده شود. توکنهای دسترسی هویت را برای فراخوانیهای فوری API اثبات میکنند، در حالی که توکنهای تازهسازی که به صورت ایمنتری ذخیره میشوند، برای دریافت توکنهای دسترسی جدید استفاده میشوند.
const jwt = require('jsonwebtoken');
const generateAccessToken = (user) => {
return jwt.sign(
{ userId: user.id, role: user.role },
privateKey,
{
algorithm: 'RS256',
expiresIn: '15m' // Short-lived access token
}
);
};
const generateRefreshToken = (user) => {
return jwt.sign(
{ userId: user.id },
privateKey,
{
algorithm: 'RS256',
expiresIn: '7d' // Long-lived refresh token
}
);
};
3. پیادهسازی لغو توکن
از آنجا که JWTها بدون حالت هستند، لغو آنها قبل از انقضا به صورت بومی پشتیبانی نمیشود. برای رفع این مشکل، میتوانید یک «لیست سیاه» یا «لیست مسدودی» برای توکنهایی که به صراحت لغو شدهاند (مثلاً هنگام خروج یا تغییر رمز عبور) پیادهسازی کنید. برای توکنهای کوتاهمدت، این موضوع کمتر حیاتی است، اما برای توکنهای تازهسازی ضروری است.
در عوض، از ادعای «jti» (شناسه JWT) استفاده کنید و شناسههای توکن صادر شده را در یک ذخیرهسازی کلید-مقدار سریع مانند Redis ذخیره کنید. قبل از پردازش یک درخواست، بررسی کنید که آیا jti در ذخیرهسازی وجود دارد یا خیر.
// Pseudocode for checking revoked tokens
async function isTokenRevoked(jti) {
const revoked = await redisClient.get(`revoked:${jti}`);
return revoked === 'true';
}
4. ذخیرهسازی ایمن در سمت کلاینت
محل ذخیرهسازی JWT در سمت کلاینت، قرارگیری آن را در برابر حملات اسکریپتنویسی بین سایتی (XSS) و جعل درخواست بین سایتی (CSRF) تعیین میکند. ذخیره توکنها در localStorage آنها را در دسترس هر اسکریپت جاوااسکریپتی که در مرورگر اجرا میشود قرار میدهد و حملات XSS را تسهیل میکند. در عوض، از کوکیهای HTTP-only استفاده کنید. این کوکیها برای جاوااسکریپت غیرقابل دسترسی هستند و دزدی مبتنی بر XSS را به طور مؤثر خنثی میکنند.
هنگام استفاده از کوکیها، مطمئن شوید که ویژگی SameSite را روی Strict یا Lax تنظیم کردهاید تا از حملات CSRF جلوگیری کنید. علاوه بر این، همیشه توکنها را از طریق HTTPS منتقل کنید تا از دستکاری شدن در حملات مرد میانی جلوگیری شود.
نتیجهگیری
ایمنسازی احراز هویت JWT یک راهاندازی یکباره نیست، بلکه فرآیندی مداوم برای ارزیابی الگوریتمها، عمر توکنها و مکانیسمهای ذخیرهسازی است. با پیادهسازی الگوریتمهای نامتقارن قوی، زمانهای انقضای کوتاه، استراتژیهای لغو و شیوههای ذخیرهسازی ایمن، میتوانید سطح حمله برنامه خود را به طور قابل توجهی کاهش دهید. به یاد داشته باشید، هیچ اقدام واحدی بینقص نیست؛ دفاع در عمق کلید حفظ امنیت قوی در جریان احراز هویت شما است.