فك تشفير JWT
فك تشفير وفحص JSON Web Tokens
رمز JWT
ما هو JWT (JSON Web Token)؟
JSON Web Token (JWT) هو تنسيق رمز مضغوط وآمن لعناوين URL، معرَّف في RFC 7519. يُشفِّر مجموعة من المطالبات (claims) كائنَ JSON ثم يوقِّعه — ويشفِّره اختياريًا — حتى يتمكن المستلم من التحقق من أن البيانات لم تُعبَث بها. تُعدّ JWT المعيارَ الفعلي للمصادقة عديمة الحالة في REST API وأنظمة الدخول الموحَّد وتفويض الخدمات المصغَّرة.
تشريح JWT: Header · Payload · Signature
يتكون كل JWT من ثلاثة أجزاء مُشفَّرة بـ base64url تفصل بينها نقاط. Header وPayload عبارة عن JSON عادي — يمكن لأي شخص قراءته — بينما Signature قيمة تشفيرية لا يمكن التحقق منها إلا بالمفتاح الصحيح.
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VyMTIzIiwibmFtZSI6IkFsaWNlIiwicm9sZSI6ImFkbWluIiwiaWF0IjoxNzE3MjAwMDAwLCJleHAiOjE3MTcyMDM2MDB9.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
{
"alg": "HS256",
"typ": "JWT"
}{
"sub": "user123",
"name": "Alice",
"role": "admin",
"iat": 1717200000,
"exp": 1717203600
}لماذا تستخدم مُفكِّك JWT؟
تبدو JWT الخام كنص عشوائي. تعرض هذه الأداة Header وPayload فورًا بتنسيق JSON مرتَّب، مما يتيح لك فحص المطالبات والتحقق من أوقات انتهاء الصلاحية ومراجعة اختيارات الخوارزمية دون كتابة سطر واحد من التعليمات البرمجية.
مرجع المطالبات القياسية لـ JWT
يُعرِّف RFC 7519 سبعة أسماء مطالبات مسجَّلة. ليست إلزامية، لكن استخدامها موصى به بشدة لضمان التشغيل البيني. يمكنك إضافة أي مطالبات مخصصة إلى Payload.
| المطالبة | الوصف | النوع |
|---|---|---|
| iss | المُصدِر — يُعرِّف من أصدر الرمز — مثل عنوان URL لخادم المصادقة أو اسم التطبيق. | string |
| sub | الموضوع — يُعرِّف الكيان الذي يتعلق به JWT — عادةً معرِّف مستخدم أو حساب خدمة. | string |
| aud | الجمهور — يُعرِّف المستلمين المقصودين. يجب على الطرف المستلم التحقق من أن هذا يطابق معرِّفه. | string | string[] |
| exp | وقت الانتهاء — طابع Unix الزمني الذي لا يُقبَل الرمز بعده. احرص دائمًا على تعيينه للحد من الضرر الناجم عن سرقة الرمز. | number |
| nbf | ليس قبل — طابع Unix الزمني الذي لا يُقبَل الرمز قبله. مفيد لجدولة رموز ذات تاريخ مستقبلي. | number |
| iat | أُصدِر في — طابع Unix الزمني الذي أُصدِر فيه الرمز. يُستخدَم لحساب عمر الرمز. | number |
| jti | JWT ID — معرِّف فريد للرمز. يُتيح الإلغاء عبر تخزين قيم JTI المستخدَمة والتحقق منها من جانب الخادم. | string |
خوارزميات توقيع JWT
يُعلن مطالبة الرأس alg عن الخوارزمية التي وقَّعت الرمز. يؤثر الاختيار على الأمان والأداء وقدرة الخدمات الخارجية على التحقق من الرموز دون المفتاح الخاص.
| الخوارزمية | العائلة | نوع المفتاح | ملاحظات |
|---|---|---|---|
| HS256 | HMAC | Symmetric | الأكثر شيوعًا. سر مشترك — يمكن لأي شخص لديه السر التوقيع والتحقق. |
| HS384 | HMAC | Symmetric | نوع HMAC أقوى؛ تكلفة أداء معتدلة. |
| HS512 | HMAC | Symmetric | النوع الأقوى من HMAC. |
| RS256 | RSA | Asymmetric | الخوارزمية غير المتماثلة الأوسع استخدامًا (Google وAuth0 وOkta). يتحقق المفتاح العام دون المفتاح الخاص. |
| RS384 | RSA | Asymmetric | نوع RS بأمان أعلى. |
| RS512 | RSA | Asymmetric | النوع الأقوى من RS. |
| ES256 | ECDSA | Asymmetric | منحنى بيضاوي — توقيعات أقصر من RSA، شائع على الجوال وIoT. |
| PS256 | RSA-PSS | Asymmetric | RSA-PSS: أكثر حداثةً وأمانًا من RS256 القائم على PKCS1v1.5. |
| none | — | — | بلا توقيع — خطير للغاية. لا تقبل أبدًا رموزًا بـ alg: none في بيئة الإنتاج. |
اعتبارات الأمان
فك تشفير JWT آمن دائمًا. أما الثقة بـ JWT دون التحقق السليم من التوقيع فليست كذلك. ضع هذه القواعد في اعتبارك في كل مرة تستخدم فيها الرموز في تطبيقك.
- –فك تشفير JWT وفحصه في أدوات المطوِّر أو هذه الأداة
- –استخدام exp وiat وnbf لفهم عمر الرمز
- –تسجيل مطالبات Payload لأغراض التصحيح (مع إغفال البيانات الشخصية الحساسة)
- –قراءة رأس alg لفهم كيفية توقيع الرمز
- –الوثوق بمطالبات Payload دون التحقق من التوقيع من جانب الخادم
- –قبول رموز بـ alg: none — يعني ذلك عدم وجود توقيع على الإطلاق
- –تخزين رموز الوصول في localStorage في تطبيقات عالية الأمان (يُفضَّل استخدام ملفات تعريف الارتباط httpOnly)
- –تعيين exp بعيدًا في المستقبل لرموز تحمل أذونات حساسة
حالات الاستخدام الشائعة
فك تشفير JWT في الكود
Header وPayload مُشفَّران بـ base64url — ما عليك سوى عكس التشفير. يستبدل base64url + بـ - و/ بـ _، ويُغفل حشو =. Signature وحدها تحتاج إلى المفتاح السري.
function decodeJWT(token) {
const [, payload] = token.split('.')
const json = atob(payload.replace(/-/g, '+').replace(/_/g, '/'))
return JSON.parse(json)
}const [, payload] = token.split('.')
const decoded = JSON.parse(
Buffer.from(payload, 'base64url').toString()
)import base64, json
def decode_jwt(token):
payload = token.split('.')[1]
padding = '=' * (-len(payload) % 4)
return json.loads(base64.urlsafe_b64decode(payload + padding))TOKEN="eyJhbGc..." echo $TOKEN | cut -d. -f2 | base64 -d 2>/dev/null | jq .