الـ JWT من جوه
الـ JWT بيانات encoded مش encrypted، ومعاها signature. الدرس ده بيفكّ الـ token جزء جزء (Header و Payload و Signature)، وبيوريك التوقيع بيتعمل إزاي بـ secret واحد (HS256) أو بزوج مفاتيح (RS256)، وبيحطك قدام 5 هجمات حقيقية لحد ما تعرف تقفلهم كلهم.
- تفك أي JWT وتعرف أجزاؤه التلاتة والـ claims المهمة
- تفهم إن الـ JWT العادي signed مش encrypted، وده يفرق في إيه
- تفرّق بين HS256 و RS256، وتعرف الـ JWKS والـ kid بيعملوا إيه
- تقفل هجمات alg none، و algorithm confusion، والـ secret الضعيف، والـ claims المنسية
1. الـ JWT (JSON Web Token)
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI3Iiwicm9sZSI6ImN1c3RvbWVyIn0.Hk3n…
└─ header ──────────────────────────┘ └─ payload ───────────────────────────┘ └─ signature| الجزء | فيه إيه | مثال بعد الفك |
|---|---|---|
| Header | نوع التوقيع | {"alg":"HS256","typ":"JWT"} |
| Payload | البيانات، واسمها claims | {"sub":"7","role":"customer","exp":…} |
| Signature | ختم بيثبت إن أول جزئين متغيروش | HMAC أو RSA للجزئين اللي قبله |
أول جزئين مكتوبين بـ Base64URL، وده نسخة من Base64 مناسبة للـ URLs. ولو فاكر المرحلة الأولى، Base64 مش تشفير. يعني أي حد معاه الـ JWT يقدر يقرا الـ payload كله.
الـ Claims المسجّلة (Registered Claims)
| الـ Claim | معناه | لازم تتشيك عليه؟ |
|---|---|---|
iss |
Issuer: مين اللي طلّع الـ token | أيوه، يكون السيرفر اللي إنت مستنيه |
sub |
Subject: الـ token ده عن مين (غالباً user id) | ده اللي هتجيب بيه المستخدم |
aud |
Audience: الـ token ده معمول لمين | أيوه، يكون إنت. ده بيمنع token معمول لـ service تانية يتستخدم عندك |
exp |
Expiration: بينتهي إمتى | أيوه، دايماً |
nbf |
Not Before: ميشتغلش قبل إمتى | لو موجود |
iat |
Issued At: اتعمل إمتى | مفيد في الـ logout من كل الأجهزة |
jti |
JWT ID: رقم مميز للـ token | مفيد في الـ denylist |
جرّب بنفسك: فك JWT وزوّره
الـ token ده اتعمل في متصفحك دلوقتي بـ HS256 والـ secret اللي تحت. فكّه، وبعدين اضغط “زوّر” عشان تحوّل نفسك لأدمن وشوف التوقيع هيعمل إيه. وبعدين وقّع من جديد، وبعدين غيّر حرف في الـ secret.
…
…
……لو جرّبت، هتلاحظ 3 حاجات:
- أي حد يقدر يقرا الـ payload من غير الـ secret.
- أول ما تغيّر حرف واحد في الـ payload، التوقيع بيبقى غلط.
- اللي معاه الـ secret يقدر يعمل أي token هو عايزه. يعني تسريب الـ secret أخطر من تسريب أي token.
الـ JWT بيانات encoded بـ Base64URL، مش encrypted، ومعاها signature. أي حد يقدر يقرا الـ payload، لكن أي تعديل فيه بيبوّظ الـ signature، والسيرفر بيرفض الـ token.
2. التوقيع: HS256 و RS256
HS256 زي ختم وحيد: اللي يقدر يتأكد من الختم، يقدر كمان يختم بيه. ده كويس لو سيرفر واحد هو اللي بيعمل الـ token وهو اللي بيتأكد منه.
RS256 زي ختم الحكومة: الختم نفسه (Private Key) مع جهة واحدة بس. لكن صورة منه (Public Key) متاحة لأي حد يتأكد بيها. يعني أي حد يقدر يتأكد، ومحدش يقدر يزوّر.
ليه ده مهم؟ لما النظام يتقسم services
دوس ▶ شغّل، أو امشي خطوة خطوة بالأسهم.
- JWKS (JSON Web Key Set): endpoint بيعرض الـ Public Keys، وغالباً بيبقى على
/.well-known/jwks.json. - kid (Key ID): حقل في الـ header بيقول أنهي مفتاح اتستخدم. وده بيخليك تغيّر المفاتيح (key rotation) من غير ما الـ tokens القديمة تبوظ مرة واحدة.
- لو service اتخترقت، الهاكر هياخد Public Key بس، ومش هيقدر يعمل tokens.
استخدم HS256 لما سيرفر واحد يعمل الـ token ويتأكد منه، واستخدم RS256 أو ES256 لما services كتير محتاجة تتأكد من غير ما تقدر تزوّر.
3. هجمات الـ JWT
السيرفر اللي تحت مكتوب بأسهل طريقة: بيصدّق أي حاجة في الـ token. ابعت الـ 5 tokens المزوّرة، وبعدين شغّل إعداد إعداد وابعت تاني:
| الهجوم | إزاي | الحماية |
|---|---|---|
| alg: none | الهاكر يغيّر الـ header لـ {"alg":"none"} ويشيل التوقيع خالص. مكتبات قديمة كانت بتقرا الـ alg من الـ token نفسه، فتقول “مفيش توقيع مطلوب” وتقبله |
السيرفر هو اللي يحدد الـ algorithm المسموح، ومياخدهوش من الـ token أبداً |
| Algorithm Confusion | السيرفر بيستخدم RS256. الهاكر يعمل token بـ HS256، ويستخدم الـ Public Key كأنه secret. لو السيرفر بيقبل الاتنين، التوقيع هيطلع صح | قايمة algorithms ثابتة على السيرفر، ومفتاح واحد لكل algorithm |
| Secret ضعيف | لو الـ secret كلمة زي secret123، الهاكر ياخد أي token ويجرّب secrets offline لحد ما التوقيع يطابق |
secret عشوائي طويل، 256 bit على الأقل، ومتخزن في الـ env |
| الـ Claims المنسية | token منتهي بيتقبل لأنك متشيكتش على exp، أو token معمول لـ service تانية بيتقبل لأنك متشيكتش على aud |
دايماً اتشيك على exp و iss و aud، مش التوقيع بس |
| بيانات حساسة | مش محتاج هجوم أصلاً. أي حد يفك الـ token يقرا اللي فيه | حط الـ user id والصلاحيات بس |
متصدقش أي حاجة في الـ token قبل ما تتأكد من التوقيع بـ algorithm إنت اللي محدده، وتتشيك على exp و iss و aud.
أسئلة الإنترفيو
فكّر في إجابتك الأول، وبعدين افتح السؤال.
01الـ JWT متشفّر؟
لأ، العادي signed بس. الـ payload مكتوب Base64URL وأي حد يقراه. التوقيع بيمنع التعديل مش القراية. عشان كده مفيش داتا حساسة فيه، ولو محتاج تشفير فيه JWE.
02إيه أجزاء الـ JWT؟
Header فيه الـ algorithm، و Payload فيه الـ claims زي sub و exp و aud، و Signature على أول جزئين. بينهم نقط، وأول جزئين Base64URL.
03الفرق بين HS256 و RS256؟
HS256 secret واحد للتوقيع والتأكد، فأي حد يقدر يتأكد يقدر يزوّر. RS256 private key للتوقيع و public key للتأكد، فالـ services تتأكد لوحدها من غير ما تقدر تعمل tokens. والـ public keys بتتنشر في JWKS.
04اذكر هجمات على الـ JWT.
alg none، و algorithm confusion (RS256 لـ HS256 بالـ public key)، و secret ضعيف بيتكسر offline، وعدم التشيك على exp و aud، وبيانات حساسة في الـ payload. والحماية: algorithm ثابت على السيرفر، و secret قوي، والتشيك على كل الـ claims.
05الـ kid في الـ header بيعمل إيه؟
بيقول أنهي مفتاح اتستخدم في التوقيع. ده بيخليك تعمل key rotation: تضيف مفتاح جديد في الـ JWKS وتبدأ توقّع بيه، والـ tokens القديمة لسه بتتأكد بالمفتاح القديم لحد ما تخلص.
06إمتى تستخدم الـ aud claim؟
لما يكون عندك أكتر من service بتقبل tokens من نفس الـ issuer. كل service تتأكد إن الـ aud هو اسمها، عشان token معمول لـ shipping-api ميتستخدمش في orders-api.