Skip to content
العودة إلى المدوّنة
الأمن

أفضل ممارسات أمان JWT: الهجمات وسبل الحماية لعام 2026

احمِ رموز JWT: أوقف هجمات alg:none وخلط الخوارزميات، وثبّت الخوارزميات، وبدّل المفاتيح، وتحقّق من المطالبات، وخزّن الرموز بأمان. دليل المطوّر لعام 2026.

13 دقيقة قراءة

أفضل ممارسات أمان JWT: الهجمات وسبل الحماية وقائمة تحقّق لعام 2026

تعتمد معظم أنظمة المصادقة الحديثة على رموز JSON Web Tokens، ومع ذلك تُهمَل أفضل ممارسات أمان JWT التي تُبقيها آمنة أكثر بكثير مما ينبغي. صار JWT صيغة الاعتماد الفعلية في OAuth 2.0 وOpenID Connect وفي النداءات بين الخدمات داخل البنى المُصغّرة. وهو أيضاً مصدر سيل ثابت من ثغرات CVE كل عام، وتعود جميعها تقريباً إلى الأخطاء نفسها التي يسهل تفاديها: قبول رموز غير موقّعة، أو الوثوق بالخوارزمية التي اختارها المهاجم، أو استخدام سرّ توقيع ضعيف، أو تخطّي التحقّق من المطالبات.

يكون رمز JWT آمناً حين تتحقّق أربعة شروط معاً: أن يكون التوقيع سليماً، وأن يعجز المهاجم عن تبديل الخوارزمية، وأن تُفحَص المطالبات فعلاً، وأن يُخزَّن الرمز في مكان يصعب سرقته منه. اكسر أيّاً منها وستحصل على تجاوز للمصادقة بدل واجهة برمجية محصّنة. يستعرض هذا الدليل الهجمات الثلاثة الأهم، ثم سبل الحماية: اختيار الخوارزمية وتثبيتها، وإدارة المفاتيح، والتحقّق من المطالبات، وتخزين الرموز. وفي آخره قائمة تحقّق يمكنك لصقها مباشرة في مراجعة الكود.

كيف يحميك توقيع JWT فعلاً (وما لا يحميك منه)

قبل أن يكون لأيّ هجوم معنى، لا بد أن تستوعب حقيقة واحدة: رمز JWT مُرمَّز لا مُشفَّر. يتكوّن الرمز الموقّع من ثلاثة مقاطع بترميز Base64URL تفصلها نقاط، على هذا الشكل: header.payload.signature. الترويسة والحمولة مجرّد Base64URL لبيانات JSON، وأي شخص يحمل الرمز يستطيع قراءة كل مطالبة فيه. الصق أي رمز في محلّل JWT لدينا وسترى الترويسة والحمولة بصيغة JSON مقروءة دون الحاجة إلى أي مفتاح. الحمولة عامّة بحكم التصميم.

من أين يأتي الأمان إذاً؟ من التوقيع وحده. وهو قيمة تشفيرية تُحسَب فوق الترويسة والحمولة باستخدام سرّ (HMAC) أو مفتاح خاص (RSA، ECDSA). يستطيع المهاجم قراءة الرمز بحرّية، لكنه لا يستطيع إنتاج رمز مختلف يجتاز التحقّق دون مفتاح التوقيع. على هذه الخاصية وحدها يقوم نموذج الثقة كلّه.

تترتّب على ذلك نتيجتان. أولاً، لا تضع أسراراً في الحمولة أبداً، مثل كلمات المرور أو مفاتيح API أو البيانات الشخصية الكاملة، فهي مقروءة لكل من يعترض الرمز. ثانياً، يرتكز أمانك كلّه على خطوة واحدة: التحقّق من التوقيع تحقّقاً صحيحاً. وهي بالضبط الخطوة التي يستهدفها المهاجمون. إن أردت شرحاً أعمق لقراءة الرموز مقطعاً مقطعاً، فطالع كيفية فكّ ترميز رمز JWT.

هجمات JWT الثلاثة الحرجة (وكيف توقف كلاً منها)

معظم ثغرات JWT ليست سوى صيغ متنوّعة لفكرة واحدة: يثق الخادم بشيء يتحكّم فيه المهاجم. وفيما يلي الهجمات الثلاثة التي تكسر المصادقة من جذورها، مع آلية كلٍّ منها وإصلاحه.

1. هجوم alg:none: تجاوز عبر رمز غير موقّع

تتضمّن مواصفة JWS قيمة alg هي none، أي «غير موقّع». يحمل رمز alg:none مقطع توقيع فارغاً وينتهي رغم ذلك بنقطة لاحقة، هكذا: header.payload.. والهجوم بسيط: خذ رمزاً صحيحاً، غيّر قيمة alg في الترويسة إلى none، وبدّل المطالبات بما يحلو لك (مثلاً "role": "admin")، واحذف التوقيع. كانت مكتبات JWT الأولى تقبل ذلك افتراضياً، فيعبر الرمز المزيّف التحقّق دون عناء، بلا مفتاح ولا توقيع، وبانتحال كامل للهوية.

يمكنك معاينة شكل رمز كهذا بتحميل مثال «alg:none» في محلّل JWT لدينا، إذ يُظهِر تحذيراً أحمر صريحاً بأن الرمز غير موقّع ويجب ألّا يُقبَل للمصادقة أبداً. وإعادة إنتاج واحد بنفسك تمرين من دقيقة يرسّخ فهم التهديد.

سبيل الحماية هو قائمة سماح صريحة للخوارزميات في كل نداء تحقّق. لا تدع الإعداد الافتراضي للمكتبة يقرّر ما هو مقبول، فالإعدادات القديمة كانت متساهلة، وكلفة التصريح لا تتجاوز خياراً إضافياً واحداً.

// WRONG — the library may accept alg:none or any algorithm
jwt.verify(token, key);

// RIGHT — pin the exact algorithm you expect
jwt.verify(token, key, { algorithms: ['RS256'] });

يجب ألّا تظهر none في تلك المصفوفة أبداً. وإن كانت مكتبتك لا تتيح تثبيت الخوارزميات، فاستبدلها.

2. خلط الخوارزميات: تخفيض RS256 إلى HS256

هذه أخطر ثغرة في JWT عملياً، معروفة منذ 2015 وما زالت تُكتشَف في عمليات التدقيق حتى اليوم. تستغلّ الخوادم التي تقرّر كيف تتحقّق بناءً على حقل alg في الترويسة، وهو الجزء الوحيد من الرمز الذي يستطيع المهاجم إعادة كتابته.

إليك الآلية. يُصدِر خادمك رموز RS256، فيوقّع بمفتاح RSA خاص ويتحقّق بالمفتاح العام المقابل. وهذا المفتاح العام عامّ بحكم تعريفه، فقد يكون في نقطة JWKS أو في مستودعك. يأخذه المهاجم، ويغيّر ترويسة الرمز من RS256 إلى HS256، ويوقّع حمولة مزيّفة بـHMAC-SHA256 مستخدماً نصّ المفتاح العام سرّاً لـHMAC. وعلى جانب التحقّق، إن كان كودك يقرأ alg من الترويسة ويختار HMAC تبعاً لذلك، فإنه يحسب HMAC-SHA256 فوق الرمز مستخدماً المفتاح العام نفسه سرّاً. يتطابق التوقيعان، ويُقبَل الرمز المزيّف.

السبب الجذري هو اصطدام حقيقتين: وثوق المُتحقِّق بحقل alg الذي يتحكّم فيه المهاجم، وتوفّر مفتاح RSA العام بين يدي المهاجم ليستخدمه مفتاحاً لـHMAC. ولا تُعدّ أيّ من الحقيقتين خطأً بمفردها، فالمفتاح العام يُفترض أن يكون عاماً، وحقل alg يُفترض أن يصف الرمز. تولد الثغرة لحظة تسمح فيها منطقية التحقّق لتلك الترويسة باختيار نوع المفتاح والخوارزمية، لأن قيمة يكتبها المهاجم تصبح عندئذ هي ما يقود المسار التشفيري الذي ينفّذه الخادم.

// WRONG — verification method follows the header's alg field
jwt.verify(token, publicKeyOrSecret);

// RIGHT — hard-code the expected algorithm; never let the header choose
jwt.verify(token, publicKey, { algorithms: ['RS256'] });

ثبّت الخوارزمية غير المتماثلة صراحةً (RS256 أو ES256 فقط)، وأبقِ تحقّق HMAC على مسار كود منفصل تماماً عن مسار تحقّق RSA، واستخدم مكتبة مُصانة تميّز بين أنواع المفاتيح. يُعلِّم محلّل JWT لدينا أي رمز من عائلة HS بتحذير خلط المفتاح العام تحديداً لأن هذا الهجوم شائع جداً، فحين يظهر رمز توقّعته غير متماثل على هيئة HS256، يكون ذلك التحذير إشارتك.

3. سرّ HMAC الضعيف: هجمات القوة الغاشمة والقواميس

حين تستخدم HMAC (HS256/384/512)، يرتكز أمان الرمز كلّه على عشوائية سرّ واحد. فإن كان ذلك السرّ قصيراً، أو كلمة من قاموس، أو قيمة مثل secret أو password123، أمكن لمهاجم يلتقط رمزاً صحيحاً واحداً أن يكسره دون اتصال. أدوات مثل hashcat تجرّب مليارات المرشّحين في الثانية ضد توقيع الرمز. وما إن يسقط السرّ حتى يصبح في وسع المهاجم سكّ أي رمز يشاء، بما في ذلك اعتماد admin صالح إلى الأبد.

وخطورته الصامتة أنه يتمّ كلّياً دون اتصال. لا يطرق المهاجم نقطة تسجيل الدخول لديك، فلا حدّ معدّل يُستثار ولا أثر في سجلّاتك تلاحظه. يلتقط رمزاً واحداً، ويكسر السرّ على عتاده الخاص، ولا يعود إلا حين يصير قادراً على توقيع رموز تجتاز كل فحص لديك. والإصلاح غير قابل للمساومة: استخدم 32 بايتاً عشوائياً على الأقل (256 بِتّاً) من مصدر آمن تشفيرياً، واحفظه في مدير أسرار، لا في الكود ولا في مستودع.

// WRONG — guessable, low entropy, crackable in seconds
const secret = "password123";

// RIGHT — 256 bits from a CSPRNG, then load from KMS at runtime
const secret = require('crypto').randomBytes(32).toString('base64');

تحتاج قيمة قوية بسرعة؟ يُنتِج مولّد كلمات المرور العشوائية لدينا سلاسل عالية العشوائية تصلح مفتاحاً لـHMAC. وتودّ أن تلمس الفرق عملياً؟ وقّع رمزاً تجريبياً بسرّ قوي في منشئ JWT لدينا، الذي يعمل بالكامل داخل المتصفح فلا يغادر السرّ جهازك. وحين يعبر التحقّق حدود الثقة، أي بين خدمات متعدّدة أو مع مُتحقِّقين من طرف ثالث، توقّف عن استخدام HS256 كلّياً وانتقل إلى خوارزمية غير متماثلة، وهو ما نتناوله تالياً.

اختيار الخوارزمية الصحيحة وتثبيتها

عند اختيار الخوارزمية يُربَح هجوم الخلط أو يُخسَر، فاختر بتمعّن. الخوارزميات الثلاث التي ستستخدمها فعلاً:

الخوارزميةالنوعمفتاح التوقيع / التحقّقمتى تُستخدم
HS256متماثلة (HMAC)سرّ مشترك واحدحدّ ثقة واحد، الطرف نفسه يوقّع ويتحقّق
RS256غير متماثلة (RSA)مفتاح خاص يوقّع / مفتاح عام يتحقّقعبر الخدمات، تحقّق من طرف ثالث، تبديل JWKS
ES256غير متماثلة (ECDSA)مفتاح خاص يوقّع / مفتاح عام يتحقّقمثل RS256، بمفاتيح أصغر وأسرع، مفضّلة للأنظمة الجديدة

القاعدة قصيرة. إن وقّع الطرف نفسه وتحقّق داخل حدّ ثقة واحد، فـHS256 ملائمة وسريعة. وإن احتاج إلى التحقّق طرف غير الموقّع، كخدمة أخرى أو شريك أو عميل عام، فاستخدم خوارزمية غير متماثلة، وفضّل ES256 لأن مفاتيحها وتواقيعها أصغر بكثير من RSA عند القوة نفسها. يمكنك توقيع رموز HS256 وRS256 وES256 جنباً إلى جنب في منشئ JWT لمقارنة بنيتها وطول توقيعها.

أيّاً اخترت، يبقى سبيل الحماية المهم فعلاً واحداً: ثبّت مجموعة خوارزميات صريحة واحدة في نداء التحقّق ولا تثق بحقل alg في الترويسة أبداً. قائمة السماح هي الأساس الذي يرتكز عليه كل ما عداه.

إدارة المفاتيح وتبديلها

الخوارزميات ليست أأمن من المفاتيح وراءها، والتعامل مع المفاتيح هو ما تصمت عنه معظم الأدلّة. بالنسبة إلى HS256، يكون السرّ 32 بايتاً عشوائياً على الأقل ويقيم في مدير أسرار، مثل AWS Secrets Manager أو HashiCorp Vault أو Azure Key Vault. وبالنسبة إلى الخوارزميات غير المتماثلة، ينتمي المفتاح الخاص إلى HSM أو KMS ولا يلامس كود التطبيق أبداً؛ أما المفتاح العام فيُنشَر، عادةً عبر نقطة JWKS يجلبها المُتحقِّقون.

ينبغي أن يكون التبديل روتيناً لا حالة طوارئ. وسِم كل مفتاح بمعرّف kid (معرّف المفتاح) في ترويسة JWT ليعرف المُتحقِّقون أي مفتاح وقّع رمزاً بعينه. وأبقِ مجموعة صغيرة من المفاتيح الصالحة على جانب التحقّق، وهي المفتاح الحالي والمفتاح السابق القريب، لتظلّ الرموز الموقّعة قُبَيل التبديل قابلة للتحقّق طوال عمرها. هذا التداخل هو ما يجعل التبديل سلساً بدل أن يكون انقطاعاً.

قائمة تحقّق موجزة للمفاتيح:

  • بدّل مفاتيح التوقيع كل 90 يوماً على الأكثر، وفوراً عند أي اشتباه باختراق.
  • انشر المفاتيح العامة عبر JWKS؛ وأعطها إصدارات بـkid.
  • احفظ المفاتيح الخاصة وأسرار HMAC في KMS أو HSM، لا في git، ولا في كود العميل، ولا مكتوبة في الكود.
  • عند تسرّب، بدّل المفتاح وأبطِل رموز التحديث المعلّقة في الحال.

التحقّق من المطالبات الذي لا يمكنك تخطّيه

فحص التوقيع يثبت أن الرمز أصيل، لكنه لا يثبت أنه لك، الآن. تلك مهمّة التحقّق من المطالبات، وهي أرخص سبيل حماية يمكنك إضافته. خمس مطالبات تحتاج إلى الفحص في كل طلب:

  • exp (انتهاء الصلاحية): ارفض الرموز التي مضى وقت انتهائها.
  • nbf (غير صالح قبل): ارفض الرموز المستخدمة قبل أن تفتح نافذتها الصالحة.
  • iat (وقت الإصدار): اختيارياً ارفض الرموز القديمة على نحو غير معقول.
  • iss (المُصدِر): تأكّد من أن الرمز جاء من المُصدِر الذي تثق به.
  • aud (الجمهور): تأكّد من أن الرمز سُكّ لخدمتك أنت. وغياب فحص aud هو أشيع ثغرة صامتة، إذ يتيح إعادة تشغيل رمز صادر لواجهة برمجية ما ضد واجهة أخرى.

تتحقّق معظم المكتبات من هذه نيابةً عنك حين تمرّر القيم المتوقّعة:

jwt.verify(token, key, {
  algorithms: ['ES256'],
  issuer: 'https://auth.example.com',
  audience: 'api.example.com',
  clockTolerance: 5, // seconds, for distributed clock skew
});

اسمح بتفاوت زمني بسيط، خمس ثوانٍ نموذجية، كي لا يرفض انحرافٌ طفيف بين الخوادم رموزاً صالحة في الأصل. وقاوم رغبة توسيعه؛ فالتسامح السخيّ يوسّع النافذة التي يظل فيها رمز منتهي الصلاحية صالحاً، وهو بالضبط ما وُجد exp ليغلقه. وللتحقّق العياني من قيمتي exp وiat على رمز ما، أدرجه في محلّل JWT وحوّل الطوابع الزمنية بـمحوّل Unix timestamp لدينا.

عمر الرمز وأين تخزّن رموز JWT

الفحوص على جانب الخادم ليست سوى نصف القصّة. فالمكان الذي يحتفظ فيه العميل بالرمز يحدّد مدى سهولة سرقته، وعند التخزين يلتقي XSS واختطاف الجلسات. النمط الذي يصمد: رمز وصول قصير العمر (15 إلى 60 دقيقة) مقترن برمز تحديث منفصل أطول عمراً وقابل للإبطال.

يتلخّص قرار التخزين في مفاضلة واحدة:

موقع التخزينالتعرّض لـXSSخطر CSRFالتوصية
localStorageمرتفع، إذ يقرؤه أي JavaScript على الصفحةلا يوجدتجنّبه لرموز الجلسة
كوكي HttpOnly + Secure + SameSite=Strictمنخفض، إذ يخفى عن JavaScriptيتطلّب حماية من CSRFموصى به للجلسات

الرمز المخزّن في localStorage يقرؤه أي نص برمجي يعمل على الصفحة، فثغرة XSS واحدة تسرّب الجلسة بأكملها، ويستطيع المهاجم إعادة تشغيلها من جهازه طوال عمرها. أما كوكي HttpOnly فلا يستطيع JavaScript قراءته إطلاقاً، ما يقلّص ضرر XSS إلى ما يستطيع المهاجم فعله داخل صفحة حيّة، وهو سيّئ لكنه ليس اعتماداً مسروقاً يحمله معه. كلفة نهج الكوكي أنك تحتاج الآن إلى حماية من CSRF، لأن الكوكيز تُرسَل تلقائياً مع كل طلب؛ ويتكفّل بذلك SameSite=Strict مع رمز CSRF. أبقِ رمز الوصول قصيراً ليكون نطاق ضرر أي تسرّب صغيراً، وضع رمز التحديث في كوكي HttpOnly وSecure وSameSite. وعند تسجيل الخروج أو الاشتباه باختراق، أبطِل رمز التحديث على جانب الخادم وبدّل مفتاح التوقيع. وللسياق الأوسع حول XSS وCSRF والكوكيز الآمنة، طالع دليلنا أفضل ممارسات أمان الويب.

قائمة تحقّق أمان JWT

راجِع هذه القائمة قبل إطلاق أي مصادقة قائمة على JWT:

  • يثبّت التحقّق قائمة سماح خوارزميات صريحة ويرفض alg:none.
  • التحقّق غير المتماثل يثبّت الخوارزمية المتوقّعة في الكود ولا يقرأ alg من الترويسة أبداً (يحجب الخلط).
  • أسرار HS256 لا تقلّ عن 32 بايتاً عشوائياً، تُحمَّل من KMS.
  • المفاتيح الخاصة تقيم في HSM/KMS؛ والمفاتيح العامة تُنشَر عبر JWKS وتُعطى إصدارات بـkid.
  • مفاتيح التوقيع تُبدَّل كل 90 يوماً على الأكثر.
  • كل طلب يتحقّق من exp وnbf وiat وiss وaud، بتفاوت زمني خمس ثوانٍ أو أقل.
  • رموز الوصول تدوم 15 إلى 60 دقيقة؛ ورموز التحديث تقيم في كوكي HttpOnly.
  • لا أسرار في الحمولة، فهي مُرمَّزة لا مُشفَّرة.

الأسئلة الشائعة

هل JWT آمن افتراضياً؟

لا. يعتمد أمان JWT على الإعداد. عليك تثبيت الخوارزمية، ورفض alg:none، واستخدام سرّ أو مفتاح عالي العشوائية، والتحقّق من المطالبات. وكثيراً ما تسمح إعدادات المكتبات الافتراضية أو المتساهلة بتجاوز المصادقة.

ما أخطر ثغرة في JWT؟

خلط الخوارزميات، حيث تُخفَّض RS256 إلى HS256 ويُستخدَم المفتاح العام سرّاً لـHMAC. وهي معروفة منذ 2015 ومع ذلك ما زالت تظهر في عمليات التدقيق، لأنها تستغلّ الخوادم التي تختار طريقة التحقّق من حقل alg في الترويسة.

هل أستخدم HS256 أم RS256؟

استخدم HS256 حين يوقّع الطرف نفسه ويتحقّق داخل حدّ ثقة واحد. واستخدم RS256 أو ES256 حين يجب أن يتحقّق طرف آخر أو طرف ثالث، أو حين تحتاج إلى تبديل JWKS. وللأنظمة الجديدة، فضّل ES256: مفاتيح أصغر وأسرع بالقوة نفسها.

أين أخزّن رمز JWT؟

فضّل كوكي HttpOnly وSecure وSameSite لرموز الجلسة، لأن JavaScript لا يستطيع قراءته ولأن ثغرة XSS واحدة لا تستطيع سرقته. وتجنّب localStorage لرموز الجلسة، فأي XSS يسرّب الجلسة بأكملها لإعادة تشغيلها.

كم مرّة أبدّل مفاتيح توقيع JWT؟

بدّل كل 90 يوماً على الأكثر كروتين، وفوراً عند أي اشتباه باختراق. أعطِ المفاتيح إصدارات بـkid وأبقِ المفتاح النشط والمفتاح السابق القريب معاً على المُتحقِّق لتظلّ الرموز الموقّعة قُبَيل التبديل صالحة.

هل يمكن العبث برمز JWT؟

ليس دون مفتاح التوقيع، فلا يستطيع أي مهاجم تزوير رمز يجتاز التحقّق. لكن إن قبل خادمك alg:none، أو كان عرضةً لخلط الخوارزميات، أو استخدم سرّاً ضعيفاً، أمكن تجاوز التوقيع. وتلك إخفاقات في الإعداد، لا عيوب في JWT نفسه.

ما المطالبات التي يجب أن أتحقّق منها؟

تحقّق من exp (انتهاء الصلاحية) وnbf (غير صالح قبل) وiat (وقت الإصدار) وiss (المُصدِر) وaud (الجمهور). وغياب فحص aud هو أشيع ثغرة صامتة، إذ يتيح إعادة تشغيل رمز مخصّص لخدمة ما ضد أخرى.

الخاتمة

أمان JWT ليس معقّداً، لكن كل طبقة لا بد أن تصمد. التوقيع هو ضمانك الوحيد، فتحقّق منه تحقّقاً صحيحاً. ثبّت خوارزمية صريحة واحدة ولا تثق بحقل alg في الترويسة أبداً. استخدم مفاتيح قوية مُبدَّلة محفوظة في KMS، وتحقّق من exp وnbf وiat وiss وaud في كل طلب، وخزّن الرموز حيث لا يطالها XSS.

ولتطبيق ذلك عملياً، الصق أي رمز في محلّل JWT لدينا لفحص خوارزميته ومطالباته والتقاط مخاطر alg:none أو خلط HS، واستخدم منشئ JWT للتجربة مع التوقيع كلّياً داخل متصفّحك، فمفاتيحك لا تغادر جهازك أبداً.

الوسوم: jwt security authentication oauth api-security

مقالات ذات صلة

عرض جميع المقالات