شرح JWT وكيف يعمل ؟ وهل هو آمن بالشكل الكافي ؟
التعرف على JWT يفيدك في حماية مشاريعك البرمجية .
* السلام عليكم ورحمة الله وبركاته *
------------------
الحمد لله على جميع نِعمه علينا ما علمنا منها وما لم نعلم حمداً والصلاة والسلام على نبينا محمد اشرف الخلق والمرسلين, اما بعد :-
--------------------
# ماهو 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
}
السؤال هو : هل الحماية فيه كافية ؟ الجواب : قطعا لا غير كافية
والأسباب كالتالي :-
- المفتاح اللي استخدمته (Key1234) جدا سهل تخمينه واسهل مما تتوقع
- السبب الثاني ان 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 العميل بنفس الوقت وبيشعر ان الموضوع مضيعة وقت وبيتعب بدون اي ناتج وطبعا لازم تشملهم بالمصادقة مو بس تتركها ديكور
وهنا مكاتب برمجية استخدموها بالهناء والشفاء :-
انا ابتعدت عن المكاتب الجاهزة من اجل ايصال المعلومة بأفضل شكل ممكن وشكرا على متابعتكم واستقبل اي استفسار
والسلام خير ختام
التعليقات (1)
وعليكم السلام ورحمة الله وبركاته
موضوعك جداً مهم ولدي سؤال
التوكن عندما يتم ارساله مع الكوكيز، بالتأكيد يوجد امكانية للحصول على التوكن من خلال المتصفح، ومنها يمكن عمل req للسيرفر ويتم التخاطب مع السيرفر وكأن المستخدم يتصفح الموقع.
كيف يمكن تجنب هذا الشي ؟
انا الان لدي توكن يوزر ما، كيف امنع الحصول على البيانات ؟
لايوجد لديك حساب في عالم البرمجة؟
تحب تنضم لعالم البرمجة؟ وتنشئ عالمك الخاص، تنشر المقالات، الدورات، تشارك المبرمجين وتساعد الآخرين، اشترك الآن بخطوات يسيرة !