JWT (JSON Web Token) هو تنسيق مضغوط لنقل البيانات بين الأطراف على شكل كائن JSON محمي بتوقيع رقمي. يمكن توقيع الرمز المميز باستخدام HMAC (مفتاح متماثل) أو RSA/ECDSA (زوج غير متماثل)، مما يضمن سلامة البيانات وصحتها. وفقًا لـ IETF RFC 7519، 2015، يتم استخدام JWT في ملايين التطبيقات للمصادقة والتبادل الآمن للادعاءات وكصيغة لرمز ID Token في OpenID Connect.
الخلاصة
JSON Web Token (JWT) هو معيار مفتوح (RFC 7519) يحدد طريقة مضغوطة ومكتفية ذاتيًا لنقل المعلومات بين الأطراف على شكل كائن JSON. تسمى المعلومات في JWT claims — بيانات حول الموضوع (المستخدم) وسمات إضافية. كل claim هو زوج مفتاح-قيمة: معرف المستخدم، الدور، وقت الانتهاء، المُصدر.
يُسمى JWT مكتفيًا ذاتيًا لأن جميع المعلومات اللازمة للتحقق موجودة داخل الرمز المميز نفسه. لا يحتاج الخادم إلى الوصول إلى قاعدة بيانات أو تخزين خارجي للتحقق من صحة الرمز — يكفي التحقق من التوقيع. هذه الخاصية تجعل JWT مثاليًا للـ الأنظمة الموزعة وهندسة الخدمات المصغرة، حيث يجب على خدمات متعددة مصادقة الطلبات دون مخزن جلسات مشترك.
وفقًا لـ Auth0، 2025، أكثر من 65% من تطبيقات الجوال والويب تستخدم JWT كصيغة رئيسية للرمز المميز لمصادقة API، متجاوزة الرموز غير الشفافة ومعرفات الجلسة.
JWT يتكون من ثلاثة أجزاء مفصولة بنقاط: header.payload.signature. كل جزء هو JSON مشفر بـ Base64url. دعنا نفحص كل جزء بالتفصيل.
Header يحتوي على حقلين إلزاميين: alg (algorithm — خوارزمية التوقيع) و typ (type — نوع الرمز، دائمًا «JWT»). يمكن أن تكون الخوارزمية متماثلة (HS256 — HMAC مع SHA-256) أو غير متماثلة (RS256 — RSA مع SHA-256، ES256 — ECDSA مع P-256). الخوارزميات غير المتماثلة مفضلة لأنها تسمح للعميل بالتحقق من التوقيع دون امتلاك المفتاح السري.
مثال على header مفكوك الترميز:
{
"alg": "RS256",
"typ": "JWT",
"kid": "key-id-1"
}
Payload يحتوي على claims — بيانات حول الموضوع. تنقسم الادعاءات إلى ثلاثة أنواع: مسجلة (iss، sub، aud، exp، nbf، iat، jti)، عامة (يحددها المطور في سجل IANA)، وخاصة (متفق عليها بين الأطراف). sub (subject) هو المعرف الفريد للمستخدم. exp (expiration) هو الطابع الزمني لانتهاء الرمز. iss (issuer) هو مُصدر الرمز.
{
"sub": "user-abc-123",
"iss": "https://auth.example.com",
"aud": "my-mobile-app",
"exp": 1812345678,
"iat": 1812342078,
"role": "premium_user"
}
Signature يتم إنشاؤها بتطبيق خوارزمية التوقيع على تسلسل header و payload باستخدام مفتاح سري أو خاص. الصيغة: HMACSHA256(base64UrlEncode(header) + «.» + base64UrlEncode(payload), secret) لـ HMAC، أو RSASHA256(...) للخوارزمية غير المتماثلة. يحسب المستلم التوقيع بنفس الطريقة ويقارنه مع المستلم — إذا تطابقا، لم يتم تغيير البيانات.
سير العمل مع JWT يتكون من مرحلتين: إنشاء (إصدار) الرمز المميز بواسطة خادم المصادقة والتحقق من الرمز بواسطة العميل أو خادم الموارد. يتلقى خادم المصادقة بيانات اعتماد المستخدم، وينشئ payload مع claims ويوقعه. يتم إرسال JWT الناتج إلى العميل كاستجابة لطلب تسجيل الدخول أو في نص استجابة OAuth 2.0 / OpenID Connect.
في تطبيقات الجوال، يتم استخدام JWT على النحو التالي: بعد تسجيل الدخول بنجاح، يتلقى المستخدم رمز وصول بتنسيق JWT. يخزنه التطبيق في مخزن آمن (Keychain في iOS، EncryptedSharedPreferences في Android). مع كل طلب API، يضيف التطبيق الرأس Authorization: Bearer <token>. يتحقق خادم API من توقيع JWT، ويستخرج الادعاءات ويتخذ قرارات الوصول بناءً عليها — دون استعلام قاعدة البيانات.
وفقًا لـ Google Codelabs، 2025، استخدام JWT في Firebase Authentication يقلل عدد الطلبات إلى خادم المصادقة بنسبة 40–60% مقارنة برموز الجلسة، حيث يتم التحقق من البيانات محليًا على كل خدمة مصغرة. هذا مهم بشكل خاص للهندسات ذات الأحمال العالية، حيث تؤثر كل ملي ثانية من زمن الوصول على تجربة المستخدم. عند 50 000 طلب في الدقيقة، يمكن أن يوفر التحول إلى JWT ما يصل إلى 10 مثيلات خادم تتعامل مع طلبات الفحص.
JWT و Session Token يحلان نفس المشكلة — مصادقة الطلبات — ولكنهما يختلفان جوهريًا في الهندسة. Session Token هو سلسلة تعريف عشوائية تشير إلى بيانات الجلسة المخزنة على الخادم (مع حفظ الحالة). JWT هو رمز مكتفٍ ذاتيًا يحتوي على جميع البيانات داخل نفسه (عديم الحالة).
| المعامل | JWT | Session Token |
|---|---|---|
| تخزين البيانات | داخل الرمز (مكتفٍ ذاتيًا) | على الخادم (مخزن الجلسة) |
| التوسع | لا يتطلب تخزينًا مشتركًا | يتطلب Redis/قاعدة بيانات لخوادم متعددة |
| إلغاء الرمز | معقد (يحتاج قائمة سوداء) | بسيط (حذف الجلسة من قاعدة البيانات) |
| الحجم | كبير (500–2000 بايت) | صغير (16–64 بايت) |
| التحقق من التوقيع | تشفيري | لا يوجد (مقارنة سلاسل) |
JWT يتفوق في الأنظمة الموزعة: يمكن للخدمات المصغرة التحقق من الرمز محليًا دون مخزن مشترك. على سبيل المثال، في هندسة بخمس خدمات مصغرة، تتحقق كل خدمة من JWT في 1–2 مللي ثانية دون استدعاء شبكة، بينما يتطلب session token استعلام Redis مركزي عند كل طلب، مما يضيف 10–30 مللي ثانية من زمن الوصول. ومع ذلك، يصعب إلغاء JWT — بمجرد إصداره، يبقى صالحًا حتى انتهاء صلاحيته. Session Token سهل الإلغاء بحذف السجل من قاعدة البيانات أو Redis.
لتطبيقات الجوال، النهج المدمج — JWT بعمر قصير (15–30 دقيقة) و Refresh Token — يوفر توازنًا بين الأداء والأمان. يتم استخدام JWT للوصول إلى API، بينما يُستخدم refresh token (عادة غير شفاف) للحصول على JWT جديدة. إذا تم اختراق JWT، يحصل المهاجم على وصول لمدة 15–30 دقيقة؛ إذا تم اختراق refresh token، يتم حظر الجلسة من خلال التدوير واكتشاف إعادة الاستخدام.
أمان JWT يعتمد على التنفيذ الصحيح. أكثر الثغرات شيوعًا هي هجوم «alg none»: يغير المهاجم header الرمز إلى «alg»: «none»، ويقبل الخادم، دون التحقق من الخوارزمية، الرمز المزيف. الحماية: تحقق دائمًا من أن الخوارزمية في header تتطابق مع المتوقعة (RS256، ES256)، وارفض الرموز التي تحتوي على alg: none.
ثغرات JWT تشمل أيضًا: مفتاح سري ضعيف لـ HMAC (اختراق في دقائق)، تسرب المفتاح الخاص (توقيع أي بيانات نيابة عن الخادم)، تخزين بيانات حساسة في payload (JWT لا يشفر، بل يوقع فقط)، هجوم حقن JWK header (إدخال مفتاح عام مخصص). استخدام المكتبات الموثوقة — Nimbus JOSE + JWT، jjwt (io.jsonwebtoken)، PyJWT — يقلل من خطر استغلال هذه الثغرات.
إجراء أمان إضافي هو JWK Thumbprint (RFC 7638): ربط مفتاح عام بالرمز عبر بصمة (thumbprint) في header. إذا خزن الخادم البصمة المتوقعة لكل عميل، يصبح حقن JWK header مستحيلًا — يرفض الخادم أي مفتاح لا يتطابق مع المسجل. توصي OAuth Security Workshop 2025 باستخدام JWK Thumbprint كحماية إلزامية لجميع JWT المستخدمة في التطبيقات المالية والطبية.
مكتبة jjwt (auth0/java-jwt) تسمح بإنشاء والتحقق من JWT في تطبيق Android في بضعة أسطر. في المثال أدناه، يولد الخادم رمزًا مع sub و role، ويتحقق العميل من التوقيع. للتخزين الآمن للمفتاح السري على الخادم، استخدم متغيرات البيئة أو HSM (وحدة أمان عتادية) — تخزين المفتاح في الكود أو ملف التكوين هو خطأ أمني جسيم.
val secret = "my-256-bit-secret-key-here"
val token = JWT.create()
.withSubject("user-abc-123")
.withIssuer("auth.example.com")
.withClaim("role", "premium_user")
.withExpiresAt(Date(System.currentTimeMillis() + 3600000))
.sign(Algorithm.HMAC256(secret))
// إرسال الرمز المميز إلى العميل
println("JWT: $token")
fun verifyToken(token: String): Boolean {
return try {
val decoded = JWT.require(Algorithm.HMAC256(secret))
.withIssuer("auth.example.com")
.build()
.verify(token)
// التوقيع صحيح، تم استخراج الادعاءات
println("Subject: ${decoded.subject}")
true
} catch (e: Exception) {
println("الرمز المميز غير صالح: ${e.message}")
false
}
}
الأسئلة الشائعة
لا. JWT يُوقع، لا يُشفر — يمكن لأي شخص فك تشفير payload Base64 وقراءة البيانات. يجب نقل المعلومات الحساسة (كلمات المرور، أرقام البطاقات، البيانات الشخصية) فقط في شكل مشفر باستخدام JWE (JSON Web Encryption).
يوصى بـ ES256 (ECDSA مع P-256) — يوفر مستوى أمان مكافئًا لـ RSA 2048-bit مع حجم توقيع أصغر بكثير. RS256 مناسب للتوافق مع الأنظمة القديمة. HS256 (HMAC) يتطلب تبادلًا آمنًا للمفتاح السري، وهو أكثر صعوبة في الهندسة الموزعة.
لا يمكن إلغاء JWT مباشرة — يبقى صالحًا حتى exp. الحلول: استخدام عمر قصير (15–30 دقيقة)، الاحتفاظ بـ قائمة سوداء لـ jti (JWT ID) الملغاة على الخادم، أو ربط الرموز بإصدار المفتاح السري. يتم إلغاء refresh token بالطريقة القياسية — بحذفه من التخزين.
Bearer token هو مفهوم: أي رمز يمكن لحامله استخدامه للوصول. JWT هو تنسيق رمز محدد. Bearer token يمكن أن يكون JWT أو سلسلة غير شفافة. يضيف JWT الاكتفاء الذاتي والتحقق التشفيري لمفهوم Bearer.
JWT نموذجي مع توقيع RS256 يشغل 500–2000 بايت. إذا كان payload يحتوي على العديد من الادعاءات المخصصة أو تم استخدام توقيع غير متماثل بمفتاح كبير، قد يصل الحجم إلى 4–5 كيلوبايت. هذا أكبر بكثير من session token (16–64 بايت)، مما يؤثر على حجم رؤوس HTTP.
الملخص
سنقوم بتطوير تطبيق جوال جاهز
تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.
اقرأ أيضًا