شرح JWT وكيف يعمل ؟ وهل هو آمن بالشكل الكافي ؟

التعرف على JWT يفيدك في حماية مشاريعك البرمجية .

1337r00tمنذ 3 سنوات

* السلام عليكم ورحمة الله وبركاته *

------------------

الحمد لله على جميع نِعمه علينا ما علمنا منها وما لم نعلم حمداً والصلاة والسلام على نبينا محمد اشرف الخلق والمرسلين, اما بعد :-

--------------------

# ماهو JWT (JSON Web Token) :-

A JSON Web Token (JWT) is a JSON object that is defined in RFC 7519 as a safe way to represent a set of information between two parties. The token is composed of a header, a payload, and a signature.

نرى ونسمع احيانا بما يسمى JSON Web Token وهو يستخدم للمصادقة بين Client و Server ولنكن واضحين اكثر هو من استخداماته انه يستخدم في عمليات Authorization و Information Exchange ويوجد بعض السيناريوهات اللي يستخدم لكن اليوم راح نتكلم عن استخدامه في المصادقة .

----------------------

# كيف يعمل ؟ :-

يتكون JWT من ثلاث اجزاء يفرق بينها علامة DOT وهي (Header + Payload + Signature) :-

Header جزء مخصص يقوم بتعريف نفسه للسيرفر, اظهار نوعه, الهاشنق اللي يستخدمه, الخ.. . (هذه المعلومات تكون متاحة للقراءة من اي شخص)
Payload هو الجزء اللذي يحتوي على المعلومات (claims) المأخوذة من الكلاينت
للسيرفر و هو اللي يحتوي على المحتوى اللي يتحقق منه السيرفر من أجل المصادقة (هذه المعلومات تكون متاحة للقراءة من اي شخص)
Signature جزء مهمته يقوم بأخذ (Header + Payload) ويقوم بتطبيق خوارزمية
HMAC على الجزئين, لو قام المهاجم بتغيير Payload سوف يتنافى مع
Signature ويرد له بالرفض التام ف هنا نفهم ان وظيفته هي التأكيد على
المصادقة (هذه المعلومات غير متاحة للقراءة من اي شخص)

 

راح نتكلم عن كل جزء وايش ممكن يحتوي من claims (موارد) وراح نبدأ بالHeader :-

  • Header
typ مخصص لنوع التوكين او المصادقة طبعا بطبيعة الحال احنا نتحدث عن JWT فالنوع اساسا يكون (jwt)
cty لتحديد نوع القيمة هو مخصص لتحديد نوع طبيعة القيمة اللي بتدخلها, تقدر تخليها فارغة او خلها افتراضيا (jwt)
alg لتحديد نوع hmac-hash هو يخبر السيرفر نوع Signature اللي ذكرناه فوق ف مثلا لو كان قيمته HS256 فالكلاينت يخبر السيرفر بأن نوع خوارزمية HMAC المستخدمه في نوع Signature اللي فوق ذكرنا -> هي HMAC-SHA256 وهنا السيرفر يقدر يتعرف على Signature بنجاح .

وهنا مثال (JSON) :-

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

ملاحظة : الPayload لايجبرك على claims معينه يعطيك حرية الأختيار لكن فيه مدة البداية والنهاية هي اللي تفيدك وتلزمك

iss المصدر هي لتعريف المصدر للسيرفر
sub الموضوع هي لتعريف اسم الموضوع او الهدف من المصادقة للسيرفر
aud التعرف على المستلم ابي اختصرها لك ماراح اطولها معك هي مثل Authorization لكن الفرق الوحيد ان Authorization يحدد وش اللي تقدر تسويه اما aud يحدد انت مين عشان يتعرف عليك.
exp وقت انتهاء صلاحية التوكين هو اهم شيء واعتبره عن نفسي الزامي ايه نعم الزامي لأغراض أمنية وهو يحدد متى تنتهي صلاحية JWT
nbf بداية صلاحية التوكين وظيفته انك تحدد متى يبدأ صلاحية JWT
iat Timestamp فقط ضع Timestamp

تنبيه : كل اللي ذكرتهم لكم فوق هم عبارة Registered claims : يعني انهم claims محددة مسبقا وماهي الزامية

هناك مايذكر عنه اسمه Private claims وهي claims اللي يضعها المبرمج بنفسه مثال :-

{
 "WhoAmI" : "1337r00t",
 "iat" : 1556962622
}

حاليا WhoAmI يعتبر Private Claims لأنني انا وضعته بنفسي

  • Signature

هو يطبق استراتيجية خوارزمية HMAC :-

HMACSHA256(base64UrlEncode(header) + "." +base64UrlEncode(payload),secret)

طيب ليش قلنا HMACSHA256 ؟ لأن في Header قيمة alg كانت HS256 وهي اختصار HMAC-SHA256 .

 

وهذا كود PHP سويته بشكل يدوي بدون استخدام مكتبات عشان يفهمون الجميع كيف يتم انتاج JWT

<?php
function base64($data) {return rtrim(strtr(base64_encode($data), '+/', '-_'), '=');} # Filtering (URLEncode)
$whoami = '1337r00t'; // Client's User
$headers = base64(json_encode(['alg'=>'HS256','typ'=>'JWT'])); // Headers
$payload = base64(json_encode(['WhoAmI'=>$whoami,'iat'=>time()])); // Payload
$secret = 'Key1234'; // Secret Key
$signature = base64(hash_hmac('SHA256',"$headers.$payload",$secret,true)); // Signature
$jwt = "$headers.$payload.$signature"; // JWT
echo $jwt; # eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJXaG9BbUkiOiIxMzM3cjAwdCIsImlhdCI6MTU1Njk2MzY3Mn0.1_gqGBADyt1MfF59xG8PTbg49vM0XE6r0Ed7yXbSAVs
?>

 

والآن راح نتجه لموضوع الحماية :-

-------------------------------------------------

# كيف نقوم بحماية JWT ؟ :-

زي ماشفتو بعد تطبيق الكود يظهر لنا هذا Token :-

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJXaG9BbUkiOiIxMzM3cjAwdCIsImlhdCI6MTU1Njk2MzY3Mn0.1_gqGBADyt1MfF59xG8PTbg49vM0XE6r0Ed7yXbSAVs

نقدروا تجربوا موقع https://jwt.io/#debugger-io?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJXaG9BbUkiOiIxMzM3cjAwdCIsImlhdCI6MTU1Njk2MzY3Mn0.1_gqGBADyt1MfF59xG8PTbg49vM0XE6r0Ed7yXbSAVs

عشان تستعلموا عن Header و payload ايش تحتوي .

Header :-

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

Payload :-

{
 "WhoAmI" : "1337r00t",
 "iat" : 1556962622
}

 

السؤال هو : هل الحماية فيه كافية ؟ الجواب : قطعا لا غير كافية

والأسباب كالتالي :-

  1. المفتاح اللي استخدمته (Key1234) جدا سهل تخمينه واسهل مما تتوقع
  2. السبب الثاني ان Payload لو المخترق وصل للمفتاح يقدر يخترق اي عميل عندي لأن فقط بيغير قيمة WhoAmi وهذا سكربت كتبته بنفسي استخدمه في اكتشاف المفتاح :-
import jwt
orignal_jwt = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJXaG9BbUkiOiIxMzM3cjAwdCIsImlhdCI6MTU1Njk2MzY3Mn0.1_gqGBADyt1MfF59xG8PTbg49vM0XE6r0Ed7yXbSAVs'
do = lambda key : jwt.encode({'WhoAmI': '1337r00t','iat': 1556962622}, key, algorithm='HS256')
brute = open('brute_force_keys.txt','r').read().splitlines()
for x in brute:
     now = do(x)
     if now == orignal_jwt:
          print("Key: "+x)
          break

 

الأخطاء اللتي تحدث من بعض المبرمحين :-

  • يعتمدون على (Header+Payload) فقط للمصادقة وينسون اهم جوء وهو Signature
  • اضافة معلومات مغلوطة في alg Header
  • ويوجد شيء مهم يخص Payload claims للذكر :-

حتى لو وضعت key صعب التخمين اذا كنت تكتفي بمعلومات عامة وسهل الحصول عليها في Payload مثل اللي كتبت انا :-

{
 "WhoAmI" : "1337r00t",
 "iat" : 1556962622
}

فأنت لازلت تتعثر في الحماية لأن المهاجم يستطيع معرفة user اي عميل ويقدر يعدل على WhoAmI ولاتتعذر بأن المفتاح صعب تخمينه فأنت لست في وضع ينفع فيه هالكلام لأن لايوجد في هذا التخمين اي Rate limit يقدر يقعد يخمن شهور ماراح تفوت عليه ولاعملية ولاتخطئ في عملها

 

بتسألني وش الحل ؟ الحل ياعزيزي ان تكون توجد claims في Payload شبه مستحيل معرفة claim العميل الخاص مثلا تستخدم UUID وتستخد مثلا Token اخر داخل العمل مثل كذا

{
 "WhoAmI" : "1337r00t",
 "Token": "dcV7wfqdlXNjozLKJpm+ipX0cM="
 "UUID": "6fc9c5cc-f889-4e5a-a4fe-c47843eaf525"
 "iat" : 1556962622
}

بكذا المهاجم صعب عليه التعرف على Token الداخلي ومعرفة UUID العميل بنفس الوقت وبيشعر ان الموضوع مضيعة وقت وبيتعب بدون اي ناتج وطبعا لازم تشملهم بالمصادقة مو بس تتركها ديكور

 

وهنا مكاتب برمجية استخدموها بالهناء والشفاء :-

https://jwt.io/#libraries-io

 

انا ابتعدت عن المكاتب الجاهزة من اجل ايصال المعلومة بأفضل شكل ممكن وشكرا على متابعتكم واستقبل اي استفسار

 

والسلام خير ختام

7
إعجاب
7968
مشاهدات
0
مشاركة
4
متابع

التعليقات (1)

عبد الله:

وعليكم السلام ورحمة الله وبركاته

موضوعك جداً مهم ولدي سؤال

التوكن عندما يتم ارساله مع الكوكيز، بالتأكيد يوجد امكانية للحصول على التوكن من خلال المتصفح، ومنها يمكن عمل req للسيرفر ويتم التخاطب مع السيرفر وكأن المستخدم يتصفح الموقع.

كيف يمكن تجنب هذا الشي ؟

انا الان لدي توكن يوزر ما، كيف امنع الحصول على البيانات ؟

لايوجد لديك حساب في عالم البرمجة؟

تحب تنضم لعالم البرمجة؟ وتنشئ عالمك الخاص، تنشر المقالات، الدورات، تشارك المبرمجين وتساعد الآخرين، اشترك الآن بخطوات يسيرة !