ما هو مفتاح التوقيع (Signing key)؟
في سياق OpenID Connect (OIDC) ، يُستخدم مفتاح التوقيع (Signing key)، الذي يكون عادةً زوجاً من المفاتيح غير المتماثلة، لتوقيع والتحقق من رموز JSON Web Tokens (JWTs) . يستخدم مقدمو OpenID مفاتيح التوقيع لتوقيع الرموز مثل رموز الهوية (ID tokens) و رموز الوصول (access tokens) لضمان سلامتها وأصالتها.
بينما يمكن أن يكون مفهوم مفاتيح التوقيع أوسع، سنركز على كيفية استخدامها في OIDC لتأمين الرموز. وتشمل الاستخدامات الأخرى توقيع الرسائل الإلكترونية والوثائق وحزم البرمجيات، والتي يمكن أن تستند إلى نفس المبادئ.
مثال: توقيع رمز الهوية (ID token)
عندما يقوم المستخدم بالمصادقة مع مقدم OpenID، يقوم المقدم بإصدار رمز هوية يحتوي على معلومات المستخدم ( المطالبات (claims) ) ويتم توقيعه بمفتاح توقيع المقدم. نظرًا لأن رمز الهوية هو JWT، فإنه يتكون من ثلاثة أجزاء: الرأس، والحمولة، والتوقيع.
1. الرأس
لنقل إن الرأس هو:
{
"alg": "ES384",
"typ": "JWT"
}
تشير JSON إلى أن رمز الهوية موقع باستخدام خوارزمية
ECDSA مع منحنى P-384. يحدد حقل typ
نوع الرمز بأنه JWT.
2. الحمولة
تحتوي الحمولة على معلومات المستخدم الأساسية:
{
"sub": "1234567890",
"name": "Alice"
}
المطالبة sub
هي معرف المستخدم الفريد، وname
هو اسم العرض الخاص به.
3. توقيع الرمز
وفقا لصيغة JWT، ينبغي أن يتم ترميز الرأس والحمولة بـ Base64URL ويتم دمجهما مع .
للتوقيع:
{{header}}.{{payload}}
في هذه الحالة، سيكون القيمة:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkFsaWNlIn0
لنفرض أن مقدم OpenID يستخدم مفتاح الخصوصية التالي لتوقيع الرمز:
-----BEGIN PRIVATE KEY-----
MIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDBW9PDXInlNT2hjOtQr
g4pkVkyJsKia33dHrsbOG4Z77pfYN7SYZCHh9YdLXTTKinehZANiAAQX/FB1s6Gj
YnDSGCY08PRUAQ8CCRCt8Ph/VDHfLj1xSbrjp8wFf0NjH7jcfNebpV1fvu4XKbP3
Ro7h0G6elN1TMsVECJPv4ieDNkYOsgT4UboJypC5E/rmvrlJTMM6Y/k=
-----END PRIVATE KEY-----
لتوقيع الرمز، يحتاج مقدم OpenID لاستخدام مفتاح الخصوصية لتوليد توقيع بـ:
signature = sign(header + '.' + payload, private_key)
ثم يكون التوقيع المرمز بـ Base64URL هو:
Cjy6A_FHnwQBP0hRawoGTkRy8m8o0Ncc1q4BeyxYr0fxhKYmJJinIWZPXJdaAXRO9wOFuH2-UML2yWHjot_LnCPO6362asMvgNkEJMZ6UtqyOPlsCOJ7voTPOCT6sYu2
4. تجميع JWT
أخيرًا، يقوم مقدم OpenID بتجميع JWT بدمج الرأس والحمولة والتوقيع مع .
:
{{header}}.{{payload}}.{{signature}}
في هذه الحالة، سيكون رمز الهوية:
eyJhbGciOiJFUzM4NCIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkFsaWNlIn0.Cjy6A_FHnwQBP0hRawoGTkRy8m8o0Ncc1q4BeyxYr0fxhKYmJJinIWZPXJdaAXRO9wOFuH2-UML2yWHjot_LnCPO6362asMvgNkEJMZ6UtqyOPlsCOJ7voTPOCT6sYu2
يكون رمز الهوية الآن جاهزًا للإرسال إلى العميل (Client) لمزيد من المعالجة.
5. التحقق من الرمز
عندما يتلقى العميل رمز الهوية، يمكنه التحقق من التوقيع باستخدام المفتاح العام لمقدم OpenID. عادةً ما يتم توفير المفتاح العام عبر نقطة نهاية اكتشاف OpenID Connect (OIDC) (jwks_uri
) بتنسيق مجموعة مفاتيح شبكية جاسونية (JWKS) .
في هذا المثال، المفتاح العام هو:
-----BEGIN PUBLIC KEY-----
MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEF/xQdbOho2Jw0hgmNPD0VAEPAgkQrfD4
f1Qx3y49cUm646fMBX9DYx-43HzXm6VdX77uFymz90aO4dBunpTdUzLFRAiT7+In
gzZGDrIE+FG6CcqQuRP65r65SUzDOmP5
-----END PUBLIC KEY-----
وقيمة JWK المقابلة هي:
{
"kty": "EC",
"crv": "P-384",
"x": "F_xQdbOho2Jw0hgmNPD0VAEPAgkQrfD4f1Qx3y49cUm646fMBX9DYx-43HzXm6Vd",
"y": "X77uFymz90aO4dBunpTdUzLFRAiT7-IngzZGDrIE-FG6CcqQuRP65r65SUzDOmP5"
}
الآن، يمكن للعميل التحقق من التوقيع باستخدام المفتاح العام.
اختيار الخوارزمية المناسبة
هناك خوارزميات متعددة متاحة لتوقيع JWTs:
- الخوارزميات المتماثلة: HMAC مع عائلة SHA (مثل HS256، HS384، HS512) هي خوارزمية متماثلة تستخدم نفس المفتاح لتوقيع والتحقق. لا يوصى بها لمعظم الحالات نظرًا لحاجة الطرفين لمشاركة المفتاح السري.
- الخوارزميات غير المتماثلة: RSA (مثل RS256، RS384، RS512) و ECDSA (مثل ES256، ES384، ES512) هي خوارزميات غير متماثلة تستخدم زوجاً من المفاتيح: مفتاح خصوصية للتوقيع ومفتاحًا عامًا للتحقق.
- RSA يُستخدم على نطاق واسع ومدعوم من قبل العديد من المكتبات والمنصات. ومع ذلك، لديه حجم مفتاح وحجم توقيع أكبر بكثير مقارنةً بـ ECDSA.
- ECDSA أكثر أداءً وينشئ توقيعات أصغر، مما يجعلها خيارًا أفضل للبيئات المقيدة. نظرًا لأنه أقل شيوعًا، تأكد من أن منصتك تدعمه.
يجب أن يكون ECDSA هو الخيار المفضل للتطبيقات الجديدة نظرًا لفوائد الأداء والأمان.
سيناريوهات أخرى لمفاتيح التوقيع
بينما يركز المثال أعلاه على رموز الهوية في OIDC، فإن مفهوم مفتاح التوقيع يُستخدم على نطاق واسع في سيناريوهات متعددة، مثل توقيع الرسائل الإلكترونية والوثائق وحزم البرمجيات. تظل المبادئ الأساسية كما هي:
- بالنسبة للمفاتيح المتماثلة، يُستخدم نفس المفتاح للتوقيع والتحقق. هذا مناسب للسيناريوهات التي يمكن أن يشارك فيها الأطراف المفتاح بأمان، أو يوجد كيان واحد مسؤول عن التوقيع والتحقق.
- بالنسبة للمفاتيح غير المتماثلة، يُستخدم مفتاح الخصوصية للتوقيع، ويُستخدم المفتاح العام المقابل للتحقق. هذا مناسب لمعظم السيناريوهات التي يكون فيها الأطراف المسؤولون عن التوقيع والتحقق مختلفين.