ما هو JWT وكيف تفك ترميزه بأمان
تظهر رموز JSON Web Token في كل مكان في تطوير الويب الحديث — ترويسات المصادقة، وتدفقات OAuth، ومفاتيح API، وإدارة الجلسات. إذا عملت مع أي واجهة برمجية تتطلب رمز Bearer، فقد استخدمت JWT بالفعل. لكن معظم المطورين يتعاملون معها كبيانات مبهمة ونادرًا ما يتفقدون محتواها. فهم بنية JWT وما يعنيه كل جزء وكيفية فك ترميزه دون الوقوع في أخطاء أمنية لا يستغرق أكثر من خمس عشرة دقيقة. هذا الدليل يغطي كل ذلك.
تشريح رمز JWT
كل رمز JWT هو سلسلة من ثلاثة أجزاء مُشفَّرة بـ Base64URL تفصل بينها نقاط:
eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VyXzEyMyIsImlzcyI6Imh0dHBzOi8vYXV0aC5leGFtcGxlLmNvbSIsImF1ZCI6Imh0dHBzOi8vYXBpLmV4YW1wbGUuY29tIiwiZXhwIjoxNzQ3MDAwMDAwLCJpYXQiOjE3NDY5OTY0MDAsInNjb3BlIjoicmVhZDp1c2VycyJ9.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c التنسيق هو الترويسة.الحمولة.التوقيع. كل جزء يُشفّر معلومات مختلفة.
الترويسة
الجزء الأول هو الترويسة. بعد فك الترميز، يصبح المثال أعلاه:
{
"alg": "RS256",
"typ": "JWT"
}
يُحدد alg الخوارزمية المستخدمة لتوقيع الرمز — RS256 يعني RSA مع SHA-256. يُعرّف typ نوع الرمز. هذان الحقلان هما الحد الأدنى؛ تتضمن بعض الرموز أيضًا kid (معرّف المفتاح) لإخبار المُحقِّق بالمفتاح العام الذي يستخدمه عند تدوير مفاتيح متعددة.
الحمولة
الجزء الثاني هو الحمولة — البيانات الفعلية. بعد فك الترميز:
{
"sub": "user_123",
"iss": "https://auth.example.com",
"aud": "https://api.example.com",
"exp": 1747000000,
"iat": 1746996400,
"scope": "read:users"
} تحتوي الحمولة على ادعاءات: تصريحات حول الكيان الذي يمثله الرمز. بعض الادعاءات مُوحَّدة (تُسمى الادعاءات المسجّلة)؛ والأخرى خاصة بالتطبيق (تُسمى الادعاءات الخاصة). الحمولة مُشفَّرة بـ Base64URL، وليست مُشفَّرة تشفيرًا أمنيًا. أي شخص يحصل على سلسلة الرمز يمكنه قراءة كل ادعاء فيها.
التوقيع
الجزء الثالث هو التوقيع. يُنتَج بأخذ الترويسة والحمولة المُشفَّرتين، وتسلسلهما بنقطة، ثم توقيع النتيجة بالمفتاح السري أو المفتاح الخاص المحدد في alg:
signature = sign(
base64url(header) + "." + base64url(payload),
secretOrPrivateKey
) يسمح التوقيع لأي طرف يمتلك المفتاح العام المقابل (أو المفتاح السري، للخوارزميات المتماثلة) بالتحقق من أن الرمز صدر من مصدر موثوق وأن الترويسة والحمولة لم تُعدَّلا بعد الإصدار. حرف واحد متغيّر في الحمولة يُبطل التوقيع بالكامل.
كيفية فك ترميز JWT
فك الترميز يختلف عن التحقق. فك الترميز يقرأ البيانات الموجودة داخل الرمز فقط. التحقق يُؤكد أن الرمز أصيل وغير منتهي الصلاحية. يجب التحقق دائمًا في كود الإنتاج؛ فك الترميز وحده مفيد لأغراض التنقيح.
الخطوة 1: تقسيم الرمز
قسّم سلسلة JWT على حرف .. ستحصل على ثلاثة أجزاء. إذا حصلت على أقل من ثلاثة، فالرمز مشوّه.
الخطوة 2: فك ترميز الترويسة والحمولة
فكّ ترميز Base64URL للجزأين الأولين. Base64URL مثل Base64 القياسي لكنه يستخدم - بدلًا من + و_ بدلًا من /، بدون أحرف حشو. بعد فك الترميز، يمكنك تحليل كل جزء بوصفه JSON.
الخطوة 3: التحليل والفحص
اقرأ الادعاءات. تحقق من exp (انتهاء الصلاحية) مقابل الطابع الزمني Unix الحالي. انظر إلى iss وaud للتأكد من أن الرمز مخصص لتطبيقك. لا تثق بأي ادعاء حتى تتحقق من التوقيع.
للفحص السريع أثناء التطوير، استخدم مفكك JWT. يعمل كليًا داخل متصفحك — رمزك لا يغادر جهازك أبدًا. يمكنك أيضًا فك ترميز مقاطع base64 يدويًا باستخدام مشفر/مفكك Base64 إذا أردت رؤية البايتات الخام. للتحقق من التوقيعات في سكريبتات الاختبار، يتيح لك مولد HMAC إعادة إنتاج توقيعات HS256 بدون كتابة كود.
الخطوة 4: التحقق من التوقيع في الكود
في الإنتاج، تحقق دائمًا من التوقيع باستخدام مكتبة مبنية للغتك. لا تُنفّذ التحقق من التوقيع يدويًا. الخيارات الشائعة تشمل jose أو jsonwebtoken لـ Node.js، وPyJWT لـ Python، وgolang-jwt/jwt لـ Go، وnimbus-jose-jwt لـ Java.
مرّر الخوارزمية دائمًا بشكل صريح. لا تدع المكتبة تستنتج الخوارزمية من ترويسة الرمز.
الادعاءات المعيارية (الادعاءات المسجّلة)
يُحدد RFC 7519 مجموعة من أسماء الادعاءات المسجّلة. هذه ليست إلزامية، لكن عند وجودها يجب أن تتبع الدلالات المعيارية.
iss — المصدر
الكيان الذي أنشأ الرمز ووقّعه. عادةً عنوان URL يُعرّف خادم المصادقة (مثلًا https://auth.example.com). يجب على المُحقِّقين التحقق من أن iss يطابق قيمة متوقعة ورفض الرموز الصادرة من مصادر غير معروفة.
sub — الموضوع
المالك الذي يمثله الرمز — عادةً معرّف مستخدم، أو اسم حساب خدمة، أو معرّف جهاز. يجب أن تكون القيمة فريدة ضمن سياق المصدر. يستخدم تطبيقك sub لتحديد أي مستخدم ينتمي إليه الطلب.
aud — الجمهور
المستلم (المستلمون) المقصودون للرمز. إذا كان معرّف واجهتك البرمجية هو https://api.example.com، يجب رفض الرموز الصادرة لخدمات أخرى. عدم التحقق من aud يسمح للمهاجمين بإعادة استخدام رمز مُحصَّل من خدمة ما في خدمة مختلفة.
exp — وقت انتهاء الصلاحية
طابع زمني Unix يجب بعده ألّا يُقبَل الرمز. تحقق دائمًا من exp. رمز بلا انتهاء صلاحية يعيش فعليًا للأبد — إذا سُرق، يحصل المهاجم على وصول غير محدود.
iat — وقت الإصدار
الطابع الزمني Unix لحظة إنشاء الرمز. مفيد لاكتشاف الرموز غير المنتهية صلاحيتها تقنيًا لكنها قديمة بشكل مريب. يمكنك استخدام iat لفرض حد أقصى لعمر الرمز بغض النظر عن exp.
nbf — ليس قبل
الطابع الزمني Unix الذي يجب قبله ألّا يُقبَل الرمز. أقل شيوعًا من exp، لكنه مفيد عند إصدار رموز مسبقًا — مثلًا مهمة مجدولة لا يجب أن تبدأ حتى وقت محدد.
jti — معرّف JWT
معرّف فريد للرمز. يسمح للمصدرين بمنع هجمات إعادة تشغيل الرمز عن طريق تخزين قيم jti المستخدمة ورفض الرموز ذات المعرّفات المكررة. ضروري عندما تحتاج إلى رموز للاستخدام مرة واحدة، مثل روابط إعادة تعيين كلمة المرور.
الثغرات الأمنية
لتطبيقات JWT تاريخ من الثغرات الخفية. هذه أهمها وأجدرها بالفهم قبل شحن كود يقبل رموز JWT.
هجوم "alg: none"
كانت بعض مكتبات JWT من الأيام الأولى للمعيار تقبل رمزًا يُحدد "alg": "none" في ترويسته. يمكن للمهاجم أخذ أي رمز صالح، استبدال الخوارزمية بـ none، إزالة التوقيع، وتقبل المكتبة الضعيفة الرمز باعتباره صالحًا تمامًا — بدون توقيع مطلوب.
الحل: حدد الخوارزمية المتوقعة دائمًا بشكل صريح عند استدعاء دالة التحقق. تعامل مع أي رمز يُعلن alg: none على أنه غير صالح. عالجت معظم المكتبات الحديثة هذه الثغرة، لكن يستحق تأكيد الإعدادات الافتراضية لمكتبتك قبل الدخول للإنتاج.
ارتباك الخوارزمية (تخفيض RS256 إلى HS256)
كانت بعض المكتبات التي تدعم كلتا الخوارزميتين تستخدم حقل alg في ترويسة الرمز لتقرير كيفية التحقق. يمكن للمهاجم تغيير الخوارزمية إلى HS256، ثم توقيع الرمز باستخدام المفتاح العام للخادم كسر HMAC. يتحقق الخادم، لدى رؤيته HS256، مقابل المفتاح العام ويقبل الرمز المزوّر.
الحل نفسه: اقفل الخوارزمية في كود التحقق. لا تدع ترويسة الرمز تؤثر على الخوارزمية المستخدمة للتحقق.
قبول الرموز المنتهية الصلاحية
عدم التحقق من exp إغفال شائع — يُدخَل أحيانًا عندما يُضيف المطورون فترة سماح تنمو بلا حدود، أو عندما يُتجاوز مسار كود التحقق في فرع برمجي. تعامل مع الرمز المنتهي الصلاحية كما تعامل مع الرمز المفقود: ارفضه بـ 401 واطلب من العميل إعادة المصادقة أو استخدام رمز التحديث.
البيانات الحساسة في الحمولة
الحمولة مُشفَّرة بـ Base64URL، وليست مُشفَّرة تشفيرًا أمنيًا. يمكن لأي شخص يعترض الرمز فك ترميزه. لا تضع كلمات المرور أو أرقام بطاقات الائتمان أو أرقام الضمان الاجتماعي أو أي بيانات حساسة أخرى في الحمولة. إذا احتجت إلى نقل ادعاءات حساسة بأمان، استخدم رمز JWE (تشفير JSON على الويب) الذي يُشفّر الحمولة. رموز JWT الموقّعة بـ JWS (الحالة الشائعة) تضمن الأصالة فقط، وليس السرية.
غياب التحقق من الجمهور
تجاوز التحقق من aud يعني أن رمزًا صادرًا للخدمة A يمكن إعادة تشغيله في الخدمة B — طالما تشترك كلتاهما في نفس مفتاح التوقيع أو تثقان بنفس المصدر. في البنيات متعددة الخدمات، تحقق دائمًا من أن جمهور الرمز يطابق معرّف خدمتك.
أفضل الممارسات لعام 2026
اختر RS256 لمعظم التطبيقات
يستخدم RS256 مفتاحًا خاصًا للتوقيع ومفتاحًا عامًا للتحقق. فقط خادم المصادقة يحتفظ بالمفتاح الخاص. يمكن لأي خدمة التحقق من الرموز باستخدام المفتاح العام الذي يمكن نشره بحرية (غالبًا عبر نقطة نهاية JWKS). إذا اخترقت خدمة تحقق فردية، يكتسب المهاجمون القدرة على التحقق من الرموز — لكن ليس تزوير رموز جديدة.
يستخدم HS256 سرًا مشتركًا واحدًا لكل من التوقيع والتحقق. أي خدمة تستطيع التحقق من الرموز تستطيع أيضًا إنشاءها. في إعداد الخدمات المصغّرة، مشاركة السر عبر خدمات عديدة تزيد من نطاق الضرر عند الاختراق.
احتفظ برموز الوصول قصيرة العمر
لا يوجد آلية إلغاء مدمجة لرموز JWT — بمجرد الإصدار، يظل الرمز صالحًا حتى انتهاء صلاحيته (ما لم تُنفّذ قائمة حظر تُعيد إدخال الحالة من جانب الخادم). أوقات انتهاء الصلاحية القصيرة (15 دقيقة إلى ساعة) تُقيّد نافذة الضرر إذا سُرق رمز. اجمع رموز الوصول مع رموز تحديث طويلة العمر مخزّنة في ملفات تعريف ارتباط HttpOnly آمنة، لا في localStorage.
استخدم تدوير رمز التحديث
عندما يستخدم العميل رمز تحديث للحصول على رمز وصول جديد، أصدر رمز تحديث جديدًا وأبطل القديم. بهذه الطريقة، يُكتشف رمز التحديث المسروق في المرة القادمة التي يحاول فيها العميل الشرعي استخدام الأصلي: يرى الخادم رمز تحديث معاد استخدامه ويستطيع إلغاء الجلسة بأكملها. هذا النمط موصوف في RFC 6819 ومدعوم على نطاق واسع من خوادم التفويض الحديثة.
انشر نقطة نهاية JWKS
تنشر نقطة نهاية JSON Web Key Set (JWKS) (/.well-known/jwks.json حسب الاصطلاح) مفاتيح التوقيع العامة بتنسيق معياري. يمكن للخدمات الأخرى جلب JWKS والتحقق من الرموز دون الحاجة لتلقي مفاتيح خارج النطاق. كما يجعل هذا تدوير المفاتيح بسيطًا: أضف المفتاح الجديد إلى JWKS، وابدأ التوقيع به، ثم أزل المفتاح القديم بعد انتهاء صلاحية جميع الرموز الموجودة.
دوّر المفاتيح دوريًا
حتى لو لم يُخترق مفتاحك الخاص أبدًا، فإن تدوير المفاتيح دوريًا يُقيّد النافذة التي يمكن خلالها استخدام مفتاح مسروق لتزوير رموز. استخدم kid في ترويسات JWT للإشارة إلى مفتاح التوقيع، حتى يتمكن المُحقِّقون من اختيار المفتاح العام الصحيح من JWKS دون كسر الرموز الموجودة أثناء التدوير.
تحقق من كل ادعاء
تحقق من iss وaud وexp وnbf في كل طلب. لا تتجاوز أيًا منها لأنها تبدو زائدة في إعدادك — الشروط التي تجعلها تبدو غير ضرورية اليوم هي بالضبط الشروط التي تتغير خلال الحوادث.
JWT مقابل ملفات تعريف الارتباط للجلسات
تحل رموز JWT وجلسات الخادم نفس المشكلة — استمرارية حالة المصادقة عبر HTTP عديم الحالة — لكن بمقايضات مختلفة.
رموز JWT مكتفية بذاتها. لا يحتاج الخادم إلى الاستعلام عن قاعدة بيانات للتحقق من طلب. هذا يجعلها جذابة للأنظمة الموزعة والواجهات البرمجية التي يستهلكها عملاء جوّالون أو أطراف ثالثة. العيب أن الإلغاء يتطلب قائمة حظر (تُعيد إدخال الحالة من جانب الخادم) أو تحمّل العمر المتبقي لرمز مخترق.
ملفات تعريف الارتباط للجلسات مُتحقَّق منها من الخادم. يخزّن الخادم حالة الجلسة ويستطيع إلغاء الوصول فورًا بحذف الجلسة. ملفات تعريف الارتباط التي تحمل العلامتين HttpOnly وSecure محمية من وصول JavaScript ومن الاعتراض عبر الشبكة. العيب أن كل طلب يتطلب بحثًا في قاعدة البيانات، مما قد يصبح عنق زجاجة على نطاق واسع.
لتطبيقات الويب التقليدية ذات الصفحات المُصيَّرة من الخادم وواجهة خلفية واحدة، تظل ملفات تعريف الارتباط للجلسات خيارًا متينًا وأبسط. للواجهات البرمجية التي يستهلكها عملاء متعددون وبنيات الخدمات المصغّرة والتطبيقات الجوّالة، رموز JWT ذات انتهاء صلاحية قصير وتدوير رمز التحديث هي الخيار الأكثر عملية.
فكّ ترميز رمزك
أسرع طريقة لفحص رمز JWT هي لصقه في مفكك JWT. يُقسّم الرمز ويفك ترميز الترويسة والحمولة ويعرض الادعاءات بتنسيق مقروء — كل ذلك دون إرسال رمزك إلى أي مكان. إذا احتجت إلى ترميز أو فك ترميز سلاسل Base64URL الخام يدويًا، يتعامل مشفر/مفكك Base64 مع المتغيرَين القياسي والآمن للروابط. للتحقق من توقيعات HMAC في سكريبتات الاختبار، يتيح لك مولد HMAC إعادة إنتاج توقيع HS256 ومقارنته بما يحتوي عليه رمزك.
للمواصفة الكاملة، راجع RFC 7519 (JWT) والأمثلة التفاعلية على jwt.io.