ما هو SSL Pinning؟
SSL Pinning (Certificate Pinning) آلية أمان تجعل التطبيق يثق فقط بشهادة SSL محددة أو بمفتاح عام (public key) محدد. في تحقق SSL الاعتيادي يثق المتصفح بجميع جهات إصدار الشهادات (CA) الموثوقة؛ أما مع الـ pinning فلا يقبل التطبيق الاتصال إلا بالشهادة أو المفتاح المحدَّد.
تُستخدم هذه الآلية خصوصًا في تطبيقات الجوال وفي اتصالات API لمنع هجمات الوسيط man-in-the-middle (MITM).
أنواع الـ Pinning
| نوع الـ Pinning | ما يُثبَّت | المرونة | الأمان |
|---|---|---|---|
| Certificate Pinning | الشهادة كاملة | منخفضة | الأعلى |
| Public Key Pinning | SPKI (public key hash) | متوسطة | عالٍ |
| CA Pinning | جهة إصدار الشهادات | عالية | متوسط |
أخطاء SSL Pinning الشائعة
الخطأ 1: جُدّدت الشهادة ولم يُحدَّث الـ Pin
المشكلة الأكثر شيوعًا. عند تجديد شهادة SSL مع استخدام certificate pinning، لا يتطابق pin الشهادة الجديدة مع الموجود في كود التطبيق.
الأعراض
- التطبيق لا يستطيع إجراء طلبات API، وتظهر رسالة "SSL Handshake Error" أو "Certificate verification failed"
- الموقع يعمل في المتصفح لكن التطبيق لا يستطيع الاتصال
- يتأثر جميع المستخدمين فجأة بعد تجديد الشهادة
الحل
- استخدم Public Key Pinning: يمكن استخدام زوج المفاتيح (key pair) نفسه حتى لو تغيّرت الشهادة
- أضف Backup Pin: ثبّت دائمًا pinين على الأقل (نشط + احتياطي)
- تحديث التطبيق: انشر تحديثًا يتضمن الـ pin الجديد
الخطأ 2: تغيّر شهادة Proxy/CDN
خدمات CDN مثل Cloudflare تستخدم شهادات SSL خاصة بها. وعند تغيّر شهادة CDN يحدث عدم تطابق في الـ pin.
الحل
- تجنّب استخدام الـ pinning خلف CDN أو ثبّت الـ root CA
الخطأ 3: خطأ في Android Network Security Config
<!-- Android: res/xml/network_security_config.xml -->
<network-security-config>
<domain-config>
<domain includeSubdomains="true">api.example.com</domain>
<pin-set expiration="2026-06-01">
<!-- Aktif pin -->
<pin digest="SHA-256">base64EncodedSHA256Hash=</pin>
<!-- pin احتياطي (بـ key مختلف) -->
<pin digest="SHA-256">backupBase64Hash=</pin>
</pin-set>
</domain-config>
</network-security-config>
⚠️ تاريخ expiration مهم — عند انتهائه يتعطل الـ pinning تلقائيًا ويواصل التطبيق العمل.
الخطأ 4: تعارضات iOS ATS
// iOS: URLSession ile pinning
func urlSession(_ session: URLSession,
didReceive challenge: URLAuthenticationChallenge,
completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
guard let serverTrust = challenge.protectionSpace.serverTrust,
let serverCert = SecTrustGetCertificateAtIndex(serverTrust, 0) else {
completionHandler(.cancelAuthenticationChallenge, nil)
return
}
// قارن hash الخاص بالـ public key
}
كيف يُحسب Pin Hash؟
# Sertifikadan SPKI pin hash hesaplama
openssl x509 -in certificate.crt -pubkey -noout | \
openssl pkey -pubin -outform der | \
openssl dgst -sha256 -binary | \
openssl enc -base64
# استخراج pin من الخادم العامل
openssl s_client -connect api.example.com:443 -servername api.example.com | \
openssl x509 -pubkey -noout | \
openssl pkey -pubin -outform der | \
openssl dgst -sha256 -binary | \
openssl enc -base64
استراتيجيات آمنة لـ SSL Pinning
- فضّل Public Key Pinning: عند تجديد الشهادة يمكنك الحصول على شهادة جديدة بزوج المفاتيح نفسه
- أضف Backup pin: ثبّت دائمًا pin احتياطيًا لمفتاح عام آخر
- حدّد تاريخ انتهاء للـ pin: خاصية
expirationفي Android توفّر حماية في الحالات الطارئة - تحديث الـ pin عن بُعد: أنشئ آلية تتيح تحديث قائمة الـ pins عن بُعد
- تثبيت Root CA: الطريقة الأكثر مرونة — لا تتأثر بتجديد الشهادات ما دامت جهة الإصدار (CA) لم تتغير
HTTP Public Key Pinning (HPKP) — لم يعد مستخدمًا
كان HPKP ترويسة HTTP تُستخدم لتطبيق public key pinning في متصفحات الويب. لكن لأنه قد يجعل الموقع غير قابل للوصول بشكل دائم عند إعداده خطأً، أُزيل من المتصفحات الرئيسية بحلول عام 2020. وحلّ محله Certificate Transparency.
الخلاصة
يُعد SSL Pinning طبقة حماية قوية من هجمات MITM لتطبيقات الجوال وأمان API. لكن يجب إدارته بما يتوافق مع إجراءات تجديد الشهادات. استخدام public key pinning، وإضافة backup pin، وتحديد تاريخ expiration — هذه الممارسات الثلاث هي أنجع طريقة لتفادي الأعطال الناتجة عن الـ pinning.