ما هو JWT في حقيقته
JSON Web Token سلسلة نصية. هذه هي الحيلة كلها. فبدل أن تمنح العميل معرّف جلسة وتحتفظ بالجلسة على الخادم، تمنحه إقرارًا موقّعًا — «هذا المستخدم 4821، وهذه صلاحياته، وينتهي في 14:05» — وتدعه يحمله معه. وأي خدمة تثق بمفتاح التوقيع تستطيع قراءة الإقرار والعمل به دون سؤال قاعدة بيانات.
وهذا بعينه ما يجعل رموز JWT مريحة جدًا وخطيرة قليلًا: فالبيانات في يد العميل. الرمز الذي تُصدره يقرؤه كل من يملكه، ولا يمكن سحبه قبل انتهاء صلاحيته، وسيقبله كل ما يثق بالتوقيع. وأغلب مشاكل JWT في الإنتاج تأتي من نسيان واحدة من هذه الحقائق الثلاث.
يبدو الرمز ثلاث كتل غير مفهومة تفصلها نقطتان:
eyJhbGciOiJIUzI1NiIsImtpZCI6ImtleS0yIn0.eyJzdWIiOiI0ODIxIiwiZXhwIjoxNzY1MTExMTExfQ.3xS7_c9Nn-aQ
وهو غير مشفّر. الكتلتان الأوليان JSON عادي بترميز Base64url، وهي أبجدية آمنة للعناوين تستبدل
+ و/ بـ - و
_ وتُسقط حشو = الأخير. يستطيع أي شخص إعادتهما إلى JSON
في ثانية، وهذا بالضبط ما يفعله مفكّك ترميز JWT.
الأجزاء الثلاثة ووظيفة كل جزء
اقسم الرمز عند النقطتين فتحصل على الترويسة والحمولة والتوقيع.
الترويسة
صغيرة، وتتعلق بالمفاتيح في الغالب. alg يسمّي خوارزمية التوقيع، وtyp
يكون عادةً JWT، وkid معرّف مفتاح يخبر الطرف المُتحقِّق أي مفتاح عام يجلب
حين يكون للمُصدِر أكثر من مفتاح. وإذا توقّف رمز فجأة عن المرور بعد تدوير المفاتيح، فابدأ من
kid.
الحمولة
المطالبات: الإقرار الفعلي. بعضها مسجّل في المعيار (iss وsub و
aud وexp وnbf وiat وjti) والباقي
ما قرّر مُصدِرك إضافته: scope وroles وtenant_id وعنوان بريد
وراية ميزة.
التوقيع
رمز مصادقة أو توقيع رقمي على الجزأين الأولين، كما يظهران في السلسلة تمامًا. وهذه التفصيلة مهمة: التوقيع يغطي البايتات المُرمَّزة، لذا فإعادة بناء JSON وترميزه من جديد تنتج رمزًا لا يمرّ التحقق ولو كانت البيانات نفسها. لا تُعِد بناء رمز بدعوى «تنظيفه» أبدًا.
كيف تفكّ ترميز رمز، وبماذا تبدأ
الصق السلسلة كاملة في الفاحص، بالنقطتين. وإن نسختها من طلب فاحذف البادئة
Bearer، أو استخدم أداة تحذفها عنك. ثم اقرأ بهذا الترتيب:
- هل فُكّ ترميزه أصلًا؟ إن قال الفاحص إن الأجزاء ليست JSON صالحًا بترميز Base64url فالرمز وصل مقطوعًا أو تالفًا. وهكذا تبدو الكوكي التي بلغت حدّ الحجم، والترويسة التي انقسمت أسطرًا.
exp. انتهاء الصلاحية يفسّر معظم شكاوى «كان يعمل قبل خمس دقائق»، وهو أول ما يُستبعد.audوiss. الرمز الصادر لجمهور آخر رمز صالح تمامًا، ومن حق واجهتك البرمجية أن ترفضه.- المطالبات المخصّصة. لا معنى للجدال حول ما في
scopeإلا بعد أن تستقيم المطالبات القياسية.
فكّ الترميز محليًا حيث تستطيع. فالرمز بيانات اعتماد حيّة، ولصقه في موقع عابر خطأ من فصيلة لصق كلمة المرور نفسها: أي أداة تستحق الاستخدام تفكّ الترميز في المتصفح ولا ترسل شيئًا إلى أي مكان.
المطالبات التي تحدّد نجاح الرمز
خمس مطالبات تؤدي العمل كله تقريبًا، وكل واحدة منها قادرة وحدها على رفض الطلب.
exp— الانتهاء، كطابع زمني Unix بالثواني. ووضع قيمة بالميلي ثانية خطأ كلاسيكي: تهبط في عام 57000 فلا ينتهي الرمز أبدًا. والفاحص الجيد يعرض التاريخ الحقيقي ومدة ما مضى عليه.nbf— ليس قبل. الرمز غير صالح حتى تلك اللحظة. يُستخدم عن قصد قليلًا، وقد يُضبط سهوًا على جهاز ساعته متقدّمة.iat— وقت الإصدار. مفيد لرفض رموز لم تنتهِ تقنيًا لكنها قديمة بشكل مريب، ولكشف خلل في الساعة حين يكونiatفي المستقبل.aud— الجمهور، أي المستقبل المقصود. والـ API الذي يتخطّى هذا الفحص سيقبل برحابة صدر رمزًا أصدرته خدمتك الأخرى لنفسها، وهذا مسار حقيقي لتصعيد الصلاحيات بين الخدمات المصغّرة.iss— المُصدِر. ثبّته على المُصدِر المتوقّع بالضبط، ولا تجلب المفاتيح إلا من مجموعة المفاتيح التي ينشرها.
وjti حالة خاصة: معرّف فريد للرمز. لا يعني شيئًا إلا إذا خزّنته وفحصته، لكنه ما يجعل
إلغاء رمز واحد بعينه ممكنًا.
فكّ الترميز ليس تحققًا
هذه النقطة هي التي تُسقط الناس. فكّ الترميز يقرأ Base64url ويعرض لك JSON. يخبرك بما يقوله الرمز، ولا يخبرك شيئًا عن صحة ما يقوله.
يستطيع أي شخص أن يكتب {"sub":"1","role":"admin"} ويحوّله إلى Base64url
ويلصق أي سلسلة في آخره كأنها توقيع ويسلّمه لك. وسيُفكّ ترميزه بلا عيب في أي فاحص، وفي فاحصنا أيضًا.
ما يمنعه من العمل هو خطوة التحقق: إعادة حساب التوقيع بمفتاح المُصدِر ورفض الرمز إن لم يتطابق. وتلك
الخطوة تحتاج سرًا أو مفتاحًا عامًا، ومكانها خادمك، ولا تستطيع أي أداة متصفح أن تؤديها عنك.
فتعامل مع الفاحص كقراءة لا كدليل. «فككت ترميزه فوجدت admin» ليست نتيجة أمنية. أما «تحقّق خادمي منه فوجد admin» فهي كذلك.
لماذا يحصل رمز سليم المظهر على 401
حين يُفكّ ترميز الرمز بنجاح ويرفضه الـ API مع ذلك، فالسبب غالبًا أحد هذه:
- منتهٍ. قارن
expبساعة الخادم، لا بساعتك. - فرق في الساعة. خادم متقدّم بدقيقتين سيرفض رموزًا صدرت للتو. ومعظم المكتبات تسمح بهامش صغير لهذا السبب تحديدًا؛ فإن كان هامشك صفرًا فالأمر يستحق المراجعة.
- جمهور خاطئ. شائع حين يخدم مزوّد هوية واحد عدة واجهات برمجية.
- تدوير المفاتيح. وقّع المُصدِر بمفتاح جديد، وما زال الطرف المُتحقِّق يحتفظ
بالمجموعة القديمة في ذاكرته، فلم يعد
kidيُحلّ. - الرمز لم يصل أصلًا. ترويسة
Authorizationمفقودة أو مشوّهة، أو كوكي ضائعة، أو وسيط يحذف الترويسات. تحقّق مما وصل الخادم فعلًا قبل أن تلوم الرمز: بحث أكواد حالة HTTP و دليلنا لأكواد الحالة يساعدان على تمييز 401 من 403 الذي يعني شيئًا آخر تمامًا.
401 أم 403؟
401 يعني أن بيانات الاعتماد ناقصة أو منتهية أو غير قابلة للتحقق: أصلح الرمز. و
403 يعني أن بيانات الاعتماد كانت سليمة والجواب مع ذلك لا: أصلح الصلاحيات، أو مطالبة
scope. والخدمات التي تُعيد 401 عند فشل التصريح ترسل الناس لتتبّع خطأ في رمز لم يكن
المشكلة قط.
اختيار خوارزمية التوقيع وفحصها
عمليًا تهم عائلتان. HS256 رمز مصادقة بسرّ مشترك: من يستطيع التحقق يستطيع التوقيع أيضًا، وهذا مقبول داخل خدمة واحدة وسيّئ الملاءمة بين المؤسسات. أما RS256 وES256 فتوقّع بمفتاح خاص وتتحقق بمفتاح عام، فيستطيع الـ API أن يتحقق من رموز ما كان ليصدرها هو نفسه.
ثم هناك alg: none، رمز غير موقّع يسمح به المعيار ويجب ألّا تقبله أبدًا. هو موجود في
المعيار، أي وُجد في المكتبات، أي استُغِلّ: فالطرف المُتحقِّق الذي يأخذ الخوارزمية من ترويسة الرمز
نفسه يمكن أن يُقال له «هذا غير موقّع، فثِق به بلا تحقق». وثمة حيلة قريبة تسلّم
مُتحقِّقًا على RS256 رمزًا بـ HS256 موقّعًا باستخدام المفتاح العام كسرّ HMAC.
الدفاع سطر واحد من السياسة: قرّر أي الخوارزميات تقبل قبل أن تنظر إلى الرمز،
وارفض ما سواها. فالترويسة إشارة إلى أي مفتاح تستخدم، لا تعليمة بشأن التحقق من التوقيع. وإذا أظهر
فاحصك alg: none بالأحمر فهذا هو السبب.
ما لا يجوز وضعه في الحمولة أبدًا
لأن الحمولة مُرمَّزة لا مُشفَّرة، فكل مطالبة فيها علنية لكل من يملك الرمز — والرموز تنتهي في مخزن المتصفح، وفي السجلات، وفي أنظمة تتبّع الأخطاء، وفي تذاكر الدعم، وفي لقطات الشاشة. أبعِد عن الحمولة:
- كل ما لا تضعه في عنوان URL: كلمات المرور، ومفاتيح الـ API، وأرقام البطاقات، والبيانات الصحية.
- المعرّفات الداخلية التي تفضّل عدم نشرها: المفاتيح الأساسية في قاعدة البيانات، وأسماء المضيفين الداخلية، وشروط الترخيص.
- الكتل الكبيرة. كل طلب يحمل الرمز؛ وكيلوبايت من المطالبات كيلوبايت في كل نداء، والرموز المتضخّمة طريق مضمون لبلوغ حدود حجم الترويسات في أي وسيط.
وأبعِد الرموز عن العناوين كذلك. الرمز في سلسلة استعلام ينتهي في سجلات الخادم، وفي ترويسات
Referer، وفي سجل تاريخ المتصفح. أرسله في ترويسة Authorization، وتأكّد أن
موقعك يضبط Referrer-Policy معقولًا: يتناول ذلك
دليلنا لرؤوس الأمان، وسيخبرك
فاحص رؤوس الأمان بما ترسله اليوم.
الانتهاء والتجديد ومشكلة الإلغاء
لا يمكن استرجاع رمز JWT. فمتى صدر صار صالحًا حتى exp، أيًّا كان ما يحدث للحساب
وراءه. أوقِف مستخدمًا، وسيظل رمز وصوله يعمل حتى تنفد مدته. تلك هي ضريبة عدم سؤال قاعدة البيانات في
كل طلب.
الجواب المعتاد رمزان. رمز وصول قصير العمر — دقائق لا أيام — يحمل المطالبات ويؤدي العمل. ورمز تجديد طويل العمر يُخزَّن على الخادم، ويُفحص في قاعدة البيانات عند كل استخدام، ويمكن إلغاؤه فورًا. وإخراج مستخدم من الحساب يصبح حينها إبطال رمز التجديد وانتظار النافذة القصيرة حتى يموت رمز الوصول وحده.
اختر نافذة الانتهاء بوعي: فهي الفجوة بين سحب الوصول وتوقّف الوصول فعليًا. خمس عشرة دقيقة حلّ
وسط شائع. والساعات يصعب تبريرها؛ والأيام تعني أنه لا إلغاء لديك إطلاقًا. وإن احتجت إلغاءً فوريًا
فاحتفظ بقائمة منع لقيم jti — وعندها تعود إلى سؤال مخزن في كل طلب، وقد تكون الجلسة
التقليدية تصميمًا أبسط.
وأيًّا كان اختيارك فحلقة التتبّع واحدة: فكّ ترميز الرمز، واقرأ exp و
aud، وتأكّد من الساعة، ثم تحقّق من التوقيع على الخادم. أربع خطوات بهذا الترتيب، وتكاد
كل مشكلة في الرموز تتكشّف في الخطوتين الأوليين.
أدوات وأدلة ذات صلة:
- مفكّك ترميز JWT — فكّ ترميز أي JSON Web Token واقرأ ترويسته وحمولته ومطالباته وتاريخ انتهائه.
- مرمّز ومفكّك ترميز Base64 — رمّز النص إلى Base64 أو فكّ ترميزه، بمخرج آمن للعناوين ومعالجة صحيحة لـ UTF-8.
- شرح Base64: كيف يعمل الترميز وفكّ الترميز فعلًا — كيف يحوّل Base64 البايتات إلى نص
أسئلة شائعة
هل أستطيع فكّ ترميز JWT بدون المفتاح السري؟⌄
نعم. الترويسة والحمولة مُرمَّزتان بـ Base64url لا مُشفَّرتان، فيقرؤهما كل من يملك الرمز. والمفتاح لازم للتحقق من التوقيع فقط. ولهذا السبب نفسه لا يجوز وضع بيانات حسّاسة في الحمولة.
هل من الآمن لصق JWT في فاحص على الإنترنت؟⌄
فقط إذا كان فكّ الترميز يجري داخل متصفحك. فالرمز بيانات اعتماد حيّة حتى ينتهي، وأي أداة ترفعه إلى خادم تتعامل مع بيانات اعتمادك. فاحصنا يعمل بالكامل داخل الصفحة ولا يرسل الرمز إلى أي مكان، لكن أسلم عادة أن تستخدم رموزًا منتهية أو تجريبية حيث أمكن.
لماذا يُفكّ ترميز رمزي بنجاح ويعيد 401 مع ذلك؟⌄
فكّ الترميز يثبت أن السلسلة سليمة البنية فقط. والأسباب المعتادة هي exp مضى وقته، أو فرق في الساعة بين المُصدِر والطرف المُتحقِّق، أو aud يسمّي واجهة برمجية أخرى، أو kid لا يستطيع المُتحقِّق حلّه بعد تدوير المفاتيح.
ما الفرق بين JWT وكوكي الجلسة؟⌄
كوكي الجلسة مؤشّر: الخادم يحفظ الحالة ويراجعها في كل طلب، فيمكن إلغاؤها فورًا. أما JWT فيحمل الحالة نفسها، فلا حاجة إلى مراجعة — ولا يمكن سحب شيء قبل الانتهاء. رموز JWT أقدر على التوسّع بين الخدمات، والجلسات تمنحك التحكّم.
أستخدم HS256 أم RS256؟⌄
HS256 يشترك في سرّ واحد، فمن يستطيع التحقق يستطيع التوقيع. وهذا مقبول داخل خدمة واحدة. أما RS256 و ES256 فيوقّعان بمفتاح خاص ويتحققان بمفتاح عام، وهو ما تريده بمجرد وجود أكثر من طرف. وفي كل الأحوال ثبّت الخوارزميات المقبولة في الطرف المُتحقِّق ولا تثق بقيمة alg في الرمز أبدًا.
خبرة عملية تزيد على 15 عامًا في تطوير الويب وأمنه. يركّز على أمن الويب العملي: الحفاظ على المواقع آمنة وموثوقة وسهلة التشخيص. وُجد BuildToolForge ليجعل هذه الفحوصات مجانية وخاصة ومفهومة. تعمل الأدوات في متصفحك كلما أمكن، ولا يُخزَّن أي شيء تُدخله في أداة.
كيف نكتب أدلتنا: يُكتب كل دليل من خبرة عملية، ويُراجَع وفق المعايير الرسمية، ويُختبر بأدواتنا على نطاقات حقيقية، ونحدّثه عندما تتغير المعايير أو الأدوات. وجدت خطأً؟ راسلنا على contact@buildtoolforge.com.