Logo Logo
GitHub Designed by Logto

ما هو رمز الويب جيسون (JWT)؟

يستخدم رمز الويب جيسون (JWT) بشكل واسع في التطبيقات الحديثة والمعايير المفتوحة مثل OpenID Connect، لتسهيل المصادقة (Authentication) والتفويض (Authorization). بينما يعد RFC 7519 مرجعًا أساسيًا، إلا أنه قد يصعب فهمه للمبتدئين. في هذه المقالة، سنركز على المفاهيم الأساسية لـ JWT وسنعرضها بلغة بسيطة مع أمثلة.

لماذا نحتاج إلى JWT؟

في الوقت الحالي، من الشائع استخدام JSON لتبادل البيانات بين طرفين. فكر في كائن JSON يمثل مستخدمًا:

{
  "sub": "foo",
  "name": "John Doe"
}

sub هو اختصار لـ “subject”، وهو ادعاء معياري (claim) في OpenID Connect لتمثيل معرف المستخدم (معرّف المستخدم).

كيف يمكننا ضمان سلامة هذا الكائن JSON؟ بعبارة أخرى، كيف يمكننا التأكد من أن البيانات لم يتم التلاعب بها أثناء النقل؟ الحل الشائع هو استخدام التوقيعات الرقمية. على سبيل المثال، يمكننا استخدام التشفير بالمفتاح العام : يقوم الخادم بتوقيع كائن JSON بمفتاحه الخاص، ويمكن للعميل التحقق من التوقيع باستخدام المفتاح العام للخادم.

باختصار، يوفر JWT نهجًا قياسيًا لتمثيل كائن JSON وتوقيعه.

يمكن أيضًا استخدام JWT لتشفير كائن JSON، ولكنه ليس محور هذه المقالة.

صيغة JWT

نظرًا لوجود العديد من الخوارزميات لإنشاء التوقيعات الرقمية، فمن الضروري تحديد الخوارزمية المستخدمة لتوقيع JWT. يتم تحقيق ذلك عبر إنشاء كائن JSON:

{
  "alg": "HS256",
  "typ": "JWT"
}

alg هو اختصار لـ “algorithm”، و typ هو اختصار لـ “type”.

عادةً ما يتم تعيين typ إلى JWT بحروف كبيرة. في مثالنا، alg هو HS256، الذي يمثل HMAC-SHA256 (سنوضحها لاحقًا)، ويشير إلى أننا نستخدم هذه الخوارزمية لإنشاء التوقيع.

الآن، لدينا جميع مكونات JWT:

  • JSON الرأس: الخوارزمية والنوع
  • JSON الحمولة: البيانات الفعلية
  • التوقيع: التوقيع الذي يشمل الرأس والحمولة

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

{{header}}.{{payload}}.{{signature}}

. يعمل كفاصل.

دعونا نجمع كل شيء لإنشاء JWT:

الرأس

JSON: {"alg":"HS256","typ":"JWT"}

Base64URL تم ترميزه: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9

الحمولة

JSON: {"sub":"foo","name":"John Doe"}

Base64URL تم ترميزه: eyJzdWIiOiJmb28iLCJuYW1lIjoiSm9obiBEb2UifQ

التوقيع

في HMAC-SHA256، يتم إنشاء التوقيع باستخدام سر:

HMAC-SHA256(base64Url(header) + "." + base64Url(payload), secret)

على سبيل المثال، مع السر some-great-secret، يكون التوقيع: XM-XSs2Lmp76IcTQ7tVdFcZzN4W_WcoKMNANp925Q9g.

JWT

الـ JWT النهائي هو:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJmb28iLCJuYW1lIjoiSm9obiBEb2UifQ.XM-XSs2Lmp76IcTQ7tVdFcZzN4W_WcoKMNANp925Q9g

يمكن لأي طرف يمتلك السر التحقق من صحة هذا الـ JWT.

اختيار خوارزمية التوقيع

كما ذكرنا سابقًا، هناك العديد من الخوارزميات لإنشاء التوقيعات الرقمية. لقد استخدمنا HS256 كمثال، ولكن قد لا تكون قوية بما فيه الكفاية لأن السر يجب أن يُشَارَك بين الأطراف (مثل العميل والخادم).

في السيناريوهات الواقعية، قد تتضمن العملاء تطبيقات عامة مثل تطبيقات React التي لا يمكنها الحفاظ على السر آمنًا. لذا، النهج المفضل يشمل استخدام التشفير بالمفتاح العام (أي التشفير غير المتماثل) لتوقيع JWT. لنبدأ بالخوارزمية الأكثر شيوعًا: RSA .

RSA

RSA هو خوارزمية غير متماثلة يستخدم زوج من المفاتيح: مفتاح عام ومفتاح خاص. يستخدم المفتاح العام للتحقق من التوقيع، بينما يُستخدَم المفتاح الخاص لتوقيع.

يبدو JSON الخاص بالرأس لـ RSA هكذا:

{
  "alg": "RS256",
  "typ": "JWT"
}

RS256 تعني RSA-SHA256، مما يعني أن التوقيع يتم إنشاؤه باستخدام خوارزمية RSA ودالة الهاش SHA256. يمكنك أيضًا استخدام RS384 و RS512 لإنشاء التوقيعات باستخدام دوال الهاش SHA384 و SHA512، على التوالي.

يتم إنشاء التوقيع باستخدام المفتاح الخاص:

RSA-SHA256(base64Url(header) + "." + base64Url(payload), privateKey)

مرة أخرى، يمكننا تجميع هذه الأجزاء لإنشاء JWT، ويبدو JWT النهائي هكذا:

eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJmb28iLCJuYW1lIjoiSm9obiBEb2UifQ.{{signature}}

الآن يمكن للعميل التحقق من التوقيع دون معرفة المفتاح الخاص.

ECDSA

على الرغم من انتشار استخدام RSA، إلا أنه يعاني من أحجام توقيع أكبر، أحيانًا تتجاوز الحجم المجمع للرأس والحمولة. خوارزمية التوقيع الرقمي للمنحنيات البيضاوية (ECDSA) هي خوارزمية غير متماثلة أخرى يمكنها إنشاء توقيعات أصغر حجماً وأكثر أداءً.

لإنشاء مفتاح خاص لـ ECDSA، نحتاج إلى اختيار منحنى. هذا خارج نطاق هذه المقالة، ولكن يمكنك العثور على مزيد من المعلومات هنا .

يبدو JSON الخاص بالرأس لـ ECDSA هكذا:

{
  "alg": "ES256",
  "typ": "JWT"
}

ES256 تعني ECDSA-SHA256، مما يعني أن التوقيع يتم إنشاؤه باستخدام خوارزمية ECDSA ودالة الهاش SHA256. يمكنك أيضًا استخدام ES384 و ES512 لإنشاء التوقيعات باستخدام دوال الهاش SHA384 و SHA512، على التوالي.

يتم إنشاء التوقيع باستخدام المفتاح الخاص:

ECDSA-SHA256(base64Url(header) + "." + base64Url(payload), privateKey)

يحتفظ الـ JWT النهائي بنفس هيكل RSA ولكنه يأتي بتوقيع أقصر بشكل ملحوظ:

eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJmb28iLCJuYW1lIjoiSm9obiBEb2UifQ.{{signature}}

التحقق من JWT

التحقق من JWT هو عملية مباشرة كعملية إنشاء JWT:

  1. قم بتقسيم JWT إلى ثلاثة أجزاء (الرأس، الحمولة، والتوقيع) باستخدام الفاصل ..
  2. قم بفك تشفير الرأس والحمولة باستخدام Base64URL.
  3. تحقق من التوقيع باستخدام الخوارزمية المحددة في الرأس والمفتاح العام (للخوارزميات غير المتماثلة).

تتوفر العديد من المكتبات للمساعدة في التحقق من JWT، مثل jose لـ Node.js ومتصفحات الويب.

انظر أيضا