يظهر تدفق JWT في كل تطبيق ويب حديث - عناصر التحقق، تدفق التحديث، تحكم الوصول إلى API. كما أنه من أكثر المعايير التي تُستخدم بشكل خاطئ في الواقع. إذا كنت تبني باستخدامها، فأن تفهم ما يحتويه التذكرة، وما يعني تحليلها مقارنة بتأكيد صلاحيتها، وما يُعرف بـ "الاختصارات" التي تُضعف أمانك هو أمر لا يمكن التنازل عنه.
بنية JWT
يُعد JWT ثلاث قيم مُشفَّرة بـ base64url متصلة بحروف النقطة:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VyXzEyMyIsImVtYWlsIjoiYWxpY2VAZXhhbXBsZS5jb20iLCJpYXQiOjE3MTI3NjQ4MDAsImV4cCI6MTcxMjg1MTIwMH0.4Xr8mNkZQWpH2TvL9uY3sKdJwFqBzEcAoMnRiVePxlU
- رأس الصفحة — خوارزمية ونوع التذكرة (
alg,typ) - الحمولة — البيانات (المعلومات التي يحتاجها تطبيقك فعليًا)
- إمضاء — التوقيع باستخدام HMAC أو RSA على أول قسمين
عند التحليل، تبدو هذه البيانات على النحو التالي:
{
"sub": "user_123",
"email": "alice@example.com",
"iat": 1712764800,
"exp": 1712851200
}
لا شيء من هذا المحتوى مُشفَّر. يمكن لأي شخص يمتلك التذكرة قراءة هذه القيم. التوقيع يثبت فقط أن التذكرة لم تُعدل بعد إصدارها - ولا يخفي محتواها.
التحليل لا يعني التحقق
هذا التمييز يُربك مطورين أكثر مما ينبغي.
التحليل يقوم بتقسيم التذكرة على النقطة ويُعيد تشفير كل قسم. لا حاجة لسرّ مُخفي - أي أداة أو تعبئة بسيطة يمكن أن تفعل ذلك. إذا أردت تحليل JWT عبر الإنترنت دون تثبيت أي شيء، فضع التذكرة في IO Tools مُحلِّل JWT للحصول على تفاصيل الرأس والحمولة والانتهاء فورًا.
التحقق يُختبر صحة التوقيع باستخدام السر (أو المفتاح العام لخوارزميات غير متماثلة). كما يؤكد أن التذكرة لم تُنتهِ، وأن البيانات تتطابق مع ما تتوقعه تطبيقك. الاعتماد على تذكرة مُحلَّلة دون تحقق هو السبب وراء اختراق التحقق.
إليك نسخة من Node.js تتحقق من JWT وتحدد الحالات الشائعة:
import jwt from 'jsonwebtoken';
const SECRET = process.env.JWT_SECRET;
function verifyToken(token) {
try {
const payload = jwt.verify(token, SECRET, {
algorithms: ['HS256'], // whitelist — never allow 'none'
audience: 'myapp', // validate aud claim
});
// jwt.verify throws if exp is in the past, but be explicit:
if (payload.exp < Math.floor(Date.now() / 1000)) {
throw new Error('Token expired');
}
return payload;
} catch (err) {
// Never silently swallow verification failures
throw new Error(`Invalid token: ${err.message}`);
}
}
البيانات المهمة للتحقق منها
يُعرّف معيار JWT معايير للبيانات التي يجب أن يتحقق منها الخادم، وليس فقط قراءتها:
| مطالبة | معنى | هل يجب التحقق منها؟ |
|---|---|---|
exp | وقت انتهاء الصلاحية | بشكل دائم - لأن التذاكر القديمة تشكل سطح هجوم حقيقي |
iat | وقت إصدار | مُتَحَدِّث، مفيد لفحص عمر الاستخدام القصوى |
sub | المُستخدم (غالبًا رقم المستخدم) | نعم - تأكيد أن الرقم يتطابق مع المستخدم المتوقع |
aud | الجمهور المقصود | نعم - منع استخدام تذكرة من خدمة A على خدمة B |
تقوم معظم مكتبات JWT بالتحقق تلقائيًا exp لكن فقط إذا كنت قمت بتكوينها. اقرأ وثائق مكتابك. لا تفترض أنها مفعلة بشكل افتراضي.
أخطاء ثلاث تُسببها مطورين
1. الـ alg: none هجوم
يسمح معيار JWT بقيمة خوارزمية none، أي عدم وجود توقيع. بعض المكتبات - وخاصة القديمة - تقبل هذه القيمة وتتجاهل التحقق من التوقيع بالكامل. يمكن للاختراق إزالة التوقيع، وضع "alg": "none" في الرأس، وForgery بيانات محددة. سيثق الخادم بها.
الحل: اجعل قائمة مسموحة للخوارزميات عند التحقق. لا تقبل noneأبدًا. يوضح النص أعلاه هذا بالاعتماد على algorithms: ['HS256'].
2. عدم التحقق من انتهاء الصلاحية
الاعتماد على تحليل التذكرة واعتمادها على المحتوى دون التحقق من exp يعني أن تذكرة صدرت منذ أشهر تُقبل. إذا تم إلغاء جلسة المستخدم أو اختراق تذكرة قديمة، فلن تعرف تطبيقك ذلك.
الحل: اجعل انتهاء الصلاحية أمرًا إلزاميًا، وليس اختياريًا. لفحص وقت انتهاء تذكرة معينة، IO Tools مُدقق انتهاء الصلاحية للـ JWT يقوم بتحليل exp البيان ويعطِي لك الوقت المتبقي بدقة - مفيد لاستكشاف تدفق التحديث دون كتابة كود.
3. تخزين JWT في localStorage
يستطيع أي كود جافا سكربت الوصول إلى localStorage. يُمكن للاختراق أن يسرق تذكرة التحقق بسلاسة. إليك مقارنة خيارات التخزين:
| التخزين | خطر XSS | خطر CSRF | قابل للوصول من JavaScript | ملحوظات |
|---|---|---|---|---|
| localStorage | عالي | لا أحد | نعم | لا يُنصح باستخدامه لتوثيق التذاكر |
| sessionStorage | عالي | لا أحد | نعم | نفس المخاطر كما في localStorage |
| httpOnly cookie | لا أحد | واسطة | لا | أفضل خيار لتوثيق التذاكر؛ اعتمادًا على SameSite + تذكرة CSRF |
| التخزين في الذاكرة (متغير JS) | قليل | لا أحد | نعم (نفس السياق) | يُفقد عند التحديث؛ مناسب للتوثيق القصير |
لا يمكن للـ httpOnly cookies أن تُقرؤ من JavaScript تمامًا، مما يزيل مسار سرقة XSS بالكامل. التنازل هو مخاطر CSRF، والتي تُعالج بـ SameSite=Strict أو تذكرة CSRF.
مقارنة JWT وجلسات: التنازل الصريح
يكون JWT بدون حالة - يتحقق من خلال الخادم دون الحاجة لاسترجاع قاعدة بيانات. وهذا مفيد في أنظمة موزعة حيث لا ترغب في أن يمر كل الخدمة بقاعدة جلسة مشتركة.
لكن الوضع بدون حالة له تكلفة حقيقية: لا يمكن إلغاء تذكرة JWT قبل انتهاء صلاحيتها. إذا قام المستخدم بتسجيل الخروج أو تم اختراقه، تبقى التذكرة صالحة حتى exp. توجد حلول بديلة (قائمة منع التذاكر، صلاحية قصيرة + تذاكر تجديد) لكنها تزيد من التعقيد وغالبًا ما تعيد ما يفعله نظام الجلسة بالفعل.
استخدم JWT عندما: أنت تمتلك أكثر من خدمة تحقق من طلبات بذاتها، ترغب في تضمين أدوار/مزايا مباشرة في التذكرة، أو أن تذاكرك قصيرة العمر وقابلية إلغاء التذكرة مقبولة.
استخدم الجلسات عندما: أنت بحاجة إلى إلغاء التذكرة فورًا (يجب أن يعمل تسجيل الخروج فعليًا)، تبني تطبيقًا يُعرض على الخادم، أو عندما تفوق البساطة على القدرة على التوسع بدون حالة.
استعرض التذكرة في ثوانٍ
هل تحتاج إلى رؤية ما داخل JWT الآن؟ من خلال الطرف:
echo "YOUR.JWT.HERE" | cut -d. -f2 | base64 -d 2>/dev/null | python3 -m json.tool
أو تجاهل الطرف - ضع التذكرة في IO Tools مُحلِّل JWT للحصول على تفاصيل مُرتبة للرأس والحمولة. لا يتحقق من التوقيع في أي من الطرق؛ فقط يتم تحليلها. لقراءة انتهاء الصلاحية بسرعة دون كتابة كود، يُقدِّم مُدقق انتهاء الصلاحية للـ JWT أوقات التوقيت الدقيق والوقت المتبقي.
تثبيت ملحقاتنا
أضف أدوات IO إلى متصفحك المفضل للوصول الفوري والبحث بشكل أسرع
恵 وصلت لوحة النتائج!
لوحة النتائج هي طريقة ممتعة لتتبع ألعابك، يتم تخزين جميع البيانات في متصفحك. المزيد من الميزات قريبا!
