مقالات معمّقة حول التكنولوجيا التي تشكّل المستقبل.

مفاتيح CA الضعيفة لدى eMudhra: 5 خرافات حول PKI

سلطة شهادات موثوقة شحنت مفاتيح خاصة يمكن كسرها في أجزاء من الثانية. نختبر خمس معتقدات حول PKI وتوليد المفاتيح والتدقيق في ضوء حادثة eMudhra.

باب خزنة ضخم مفتوح لا يحميه سوى قفل لعبة صغير
استندت أمان سلطة الشهادات لسبعة عشر شهراً إلى ثمانية بتات من الإنتروبيا فقط.

أحد مفاتيح الخاصة لسلطة الشهادات التابعة لـ eMudhra هو الرقم 4. ليس رقماً من 384 بت يبدأ بالرقم 4، بل الرقم 4 فقط، مع 47 بايت صفرياً تملأ الباقي ليبدو الأمر محترماً. هذا فشل في توليد مفتاح سلطة شهادات من النوع الذي كنت سأخبرك أنه مستحيل، وقد نجا من عمليات التدقيق، ومن التوقيع المتبادل من Sectigo، وسبعة عشر شهراً في بنية تحتية قريبة من الإنتاج، قبل أن يجرّب أحدهم الخطوة الأوضح: التخمين بالقوة الغاشمة لبايت واحد. إليك خمس معتقدات حول PKI يقضي عليها هذا الحادث تماماً.

الخرافة 1: «الشهادة الصالحة بنيوياً شهادة آمنة»

كل فحص آلي في خط المعالجة قال إن هذه الشهادات سليمة، وكانوا محقين بمعنى ضيق وعديم الفائدة. المفتاح العام المقابل لـ d = 4 نقطة صالحة تماماً على منحنى P-384. تحليل ASN.1 ينجح، والتوقيع يتحقق، وسلسلة الثقة تكتمل. كل أداة lint، وكل مدقق بنيوي، وكل قائمة امتثال تفحص الشهادة وتؤكد أنها مُشكّلة بشكل صحيح ستمررها، لأنها فعلاً مُشكّلة بشكل صحيح.

هنا يكمن الفخ. التحقق البنيوي يجيب عن سؤال «هل هذه شهادة بتنسيق صحيح؟»، لكنه لا يجيب عن «هل تم توليد المفتاح الداخلي بشكل صحيح؟». في مفاتيح المنحنيات الإهليلجية، هاتان الخاصيتان مستقلتان تقريباً. المفتاح الخاص ليس سوى عددية d، والمفتاح العام هو d × G، حيث G هي نقطة المولّد للمنحنى. كامل الحجة الأمنية أن استعادة d من النقطة العامة تتطلب حل مسألة اللوغاريتم المتقطع، لكن فقط إذا اختير d فعلاً من فضاء 384 بت كامل. إذا اختير d من 8 بتات فقط، تتحول المسألة «المستحيلة» إلى حلقة تكرارية لا تتجاوز 255 خطوة.

لا شيء في الشهادة الناتجة يلمّح إلى ذلك. النقطة العامة المشتقة من d = 4 تبدو عشوائية تماماً مثل تلك المشتقة من مفتاح مُولَّد بشكل صحيح. لا يمكنك تمييزها بالنظر، ولا يمكنك فحصها بأداة lint. الطريقة الوحيدة لمعرفة ذلك هي تجربة قيم صغيرة وأنماط ضعيفة معروفة، وهذا بالضبط ما حدث: شغّل المُبلّغ مجموعة اختبارات paranoid_crypto من Google على مجموعة بيانات Common CA Database مباشرة، فحصل على نتيجة. فحص يستغرق أجزاء من الثانية على حاسوب محمول، ضد مفاتيح تمنح الثقة للمتصفحات الحقيقية.

إذن الدرس الأول: الصلاحية ضرورية، لكنها بعيدة كل البعد عن الكفاية. إذا توقف اختبار PKI لديك عند «الشهادة تُحلَّل وتُسلسَل بشكل صحيح»، فأنت تختبر الغلاف وتتجاهل المضمون.

الخرافة 2: «متطلبات الأساس وعمليات التدقيق تكشف أخطاء توليد المفاتيح»

تخضع سلطات الشهادات لمتطلبات الأساس الصادرة عن CA/Browser Forum، وتُدقَّق وفق معايير WebTrust أو ETSI. هناك وثائق الإجراءات الرسمية، ومتطلبات HSM، ومتطلبات طول المفتاح. مفاتيح eMudhra كانت بالطول الصحيح، 384 بت على الورق. الفجوة في التدقيق أن الامتثال يتحقق من تمثيل المفتاح، لا من إنتروبيا العملية التي أنتجته. مفتاح مُحشى بـ 47 بايت صفرياً ما زال يشغل 48 بايت على القرص.

وفقاً لرواية eMudhra نفسها، المنشورة في تذكرة الحادثة لدى Mozilla، فإن السبب الجذري يبدو ككوميديا سوداء: خطأ في سكربت الإجراءات ولّد زوج مفاتيح ثانياً ضعيفاً على HSM، وكان للزوجين أسماء متشابهة، واختار إنسان الزوج الخاطئ لطلب توقيع الشهادة (CSR). ثلاثة إخفاقات منفصلة: خطأ في السكربت، وتعارض في التسمية، وخطأ في الاختيار. ولم يسأل أي ضابط في أي لحظة: «هل يملك هذا المفتاح الإنتروبيا التي دفعنا ثمنها لـ HSM؟»

هذا هو الجزء الذي يجب أن يقلق كل مهندس يدير PKI داخلياً خاصاً به. إذا استطاعت سلطة شهادات موثوقة عامة، تحت ضغط برامج الجذور وعمليات التدقيق المجدولة، أن تشحن مفتاحاً خاصاً يساوي 4، فماذا يوجد داخل Vault PKI backend خاصتك أو قوالب Active Directory Certificate Services؟ الحل رخيص، ولا عذر لعدم تطبيقه. بعد توليد أي مفتاح، وقبل التوقيع به، شغّله عبر paranoid_crypto أو على الأقل فحص سلامة بسيط:

from cryptography.hazmat.primitives.asymmetric import ec
CURVE_ORDER_BITS = 384
def sanity_check_private_key(key: ec.EllipticCurvePrivateKey) -> None:
d = key.private_numbers().private_value
# Reject keys whose effective entropy is far below the curve size.
# A healthy P-384 key should have a bit length close to 384.
if d.bit_length() < CURVE_ORDER_BITS - 32:
raise ValueError(
f"Suspiciously small private scalar: {d.bit_length()} bits"
)
# Also reject known bad values outright.
if d < 2**16:
raise ValueError("Private scalar is trivially brute-forceable")

ثلاثون ثانية من العمل. كان سيكتشف كل واحد من المفاتيح الثمانية لدى eMudhra. عمليات التدقيق تتحقق من وجود الإجراءات، ولا تتحقق من أن الإجراءات نجحت فعلاً في أي ثلاثاء معين من شهر أبريل. وحده اختبار المخرجات يفعل ذلك.

الخرافة 3: «يمكن احتواء مفتاح سلطة شهادات مُخترَق»

عندما يكون مفتاح سلطة الشهادات «مُخترَقاً» بالمعنى المعتاد، يكون هناك لص. شخص سرق المفتاح في لحظة معينة، ويمكنك أن تستدل على نطاق الضرر: شهادات صادرة بعد السرقة، من أطراف تملك المفتاح المسروق. قبيح، لكنه محدود. كتبنا سابقاً عما يحدث عندما يكسر اختراق سلطة وسيطة سلسلة الثقة، وخطة الطوارئ المعتادة، أي الإلغاء وسحب الثقة وإعادة الإصدار، تفترض وجود «قبل» و«بعد».

هذا الحادث لا يملك «قبلاً» و«بعداً». المفتاح كان عملياً عاماً منذ لحظة إنشاء الشهادة، لأن أي شخص نظر إلى الشهادة كان بإمكانه استعادة المفتاح في أجزاء من الثانية. لا يوجد حدث سرقة يمكن تحديده. النافذة هي كامل عمر الشهادات، من أبريل 2025 فصاعداً، ولا توجد طريقة لمعرفة من، إن وُجد أحد، عبر الباب المفتوح. بيان eMudhra بأن السلطات الوسيطة لم تُصدر أي شهادات للكيانات النهائية، والذي تؤكده سجلات Certificate Transparency، مطمئن فعلاً بالنسبة لما فعلته تلك السلطات. لكنه لا يقول شيئاً عما كان بإمكان من يحمل d=4 أن يفعله بانتهازية على مسار شبكة ما.

والأسوأ أن الاستجابة نفسها لا يمكن أن تكتمل. Chrome وFirefox حجبتا السلطات الوسيطة خلال ساعات عبر CRLSet وOneCRL، وكلاهما يتطلب تسجيل CT، لذلك ما كانت شهادات TLS المزوّرة لتُقبل في هذين المتصفحين على أي حال. جيد. لكن هذه الحماية تنتهي عند حدود المتصفح، وهذا يقودنا إلى الخرافة التالية.

الخرافة 4: «إذا كانت المتصفحات آمنة، فالمنظومة آمنة»

نافذة متصفح مدرعة متوهجة محاطة بمئات الأجهزة المتصلة المكشوفة في الظلام
المتصفحات رُقِّعت خلال ساعات، أما بقية منظومة TLS فما زالت مكشوفة.

المتصفحات هي السيناريو الأفضل في منظومة TLS، وهي تمثل أقلية من عملاء TLS المهمين تشغيلياً بالنسبة لك. فكّر فيما يصنع اتصالات HTTPS فعلياً في بنيتك التحتية: curl، وrequests في Python، وNode، وبرامج Go الثنائية، وخدمات Java، وgit، ومديرو الحزم، وSDKs السحابية. هذه العملاء تتشارك ثلاث سمات تتراكم بشكل سيئ هنا: تثق بحزمة CA مخزنة على القرص، ولا تتحقق من الإلغاء افتراضياً، ولا تتحقق من Certificate Transparency. الحمايات الثلاث التي أنقذت مستخدمي Chrome غائبة كلها.

أوضح Scott Helme ذلك عملياً: مع شهادة مزوّرة لـ api.stripe.com تنتهي بإحدى السلطات الوسيطة الضعيفة لـ eMudhra، أبلغ curl الافتراضي بـ SSL certificate verify ok، وأكمل Python المصافحة، وأبلغ Node أن الاتصال مصرّح به، وقبلت Windows CryptoAPI السلسلة. على كل جهاز Linux وmacOS تم اختباره. شهادة مزوّرة لـأي اسم مضيف، مقبولة من الأدوات الافتراضية التي تُبنى عليها سكربتات النشر ومشغلات CI لديك. هذه ليست مشكلة متصفح، بل مشكلة في بنيتك التحتية.

خريطة التعرض أسوأ مما يتصوره معظم الناس:

  • مثبتات curl | sh ومحدّثات ذاتية. rustup وnvm ومثبت Homebrew، وعدد لا يحصى من صفحات "install.sh". شهادة مزوّرة هنا تعني تشغيل كود المهاجم، غالباً بصلاحيات root.
  • خطوط CI/CD. تسحب المشغلات التبعيات وتدفع الأدوات بينما تحمل بيانات اعتماد سحابية ومفاتيح توقيع، غالباً على صور أساسية قديمة.
  • حركة الخادم إلى الخادم. webhooks للدفع، وتبادل رموز OAuth، واستدعاءات SDK السحابية التي تحمل أسراراً في الترويسات.
  • أجهزة إنترنت الأشياء والأجهزة المدمجة. برامج ثابتة مجمدة مع حزم CA لن تتغير حتى تنتهي صلاحية الشهادات، أي في يوليو 2039.
  • توقيع الكود على Windows. اثنان من المفاتيح الثمانية الضعيفة كانا تابعين لسلطات توقيع الكود، والبرمجيات الخبيثة الموقّعة بها تبدو كبرمجيات من ناشر شرعي.

النصيحة العملية مملة وصحيحة: حدّث كل ما يحمل حزمة CA. حزمة ca-certificates في نظام التشغيل، وcertifi، وNode، وHomebrew، وأعد بناء صور الحاويات بعد أن تلتقط الصور الأساسية الإلغاء، لأن الطبقات تتذكر. الجزء غير القابل للتنفيذ هو الجهاز الذي لا يمكنك تحديثه. ذلك التلفاز الذكي سيثق بمفتاح يساوي 4 لعقد ونصف آخر. إن كنت تحتاج حجة إضافية لعزل أجهزة إنترنت الأشياء على الشبكة، فهذه هي.

الخرافة 5: «لا بد أن أحداً يتحقق من هذا بالفعل»

أكثر عبارة مُدينة بصمت في الحادث جاءت من المُبلّغ: اكتُشف الخلل عندما شغّل paranoid_crypto على مجموعة CCADB كـاختبار سريع لمجموعة البيانات قبل الانتقال إلى شهادات المشتركين. الثمرة المتدلية من أدنى الغصن. وفي كلمات المُبلّغ: «معظم وقتي قضيته في مراجعة الأساسيات التي افترض الجميع أن أحداً آخر قد أنجزها، وهو خطأ فادح لا ينبغي ارتكابه قرب الأمن.»

اقرأ ذلك مرة أخرى. ثماني مفاتيح خاصة لسلطة شهادات، وهي جواهر تاج سلطة موثوقة عامة ومتقاطعة التوقيع مع جذر AAA Certificate Services لدى Sectigo، ظلت قابلة للتخمين بالقوة الغاشمة لسبعة عشر شهراً. لم يكتشفها مدقق، ولا برنامج جذور، ولا السلطة نفسها، بل شخص واحد يشغّل أداة مفتوحة المصدر كما هي. افترضت المنظومة جماعياً أن الأساسيات مغطاة، لكن لم يغطِّها أحد.

هذا نمط أوسع في البنية التحتية الأمنية، ولهذا أظل أكرر الحديث عن الهندسة الدفاعية، أي الأنظمة التي تقاوم الكارثة، بدلاً من الأنظمة التي تفترض التشغيل الصحيح. الفحوصات التي كانت ستكتشف هذا رخيصة إلى حد محرج:

  1. شغّل paranoid_crypto أو فحوصات المفاتيح الضعيفة المكافئة على كل مفتاح عند التوليد، وعلى كل CSR قبل التوقيع.
  2. تحقق من الإنتروبيا تجريبياً: افحص طول بتات العددية الخاصة، وارفض أي شيء ذو إنتروبيا فعالة منخفضة بشكل غير معقول، كما في عينة الكود أعلاه.
  3. اختبر الإجراء لا الإعداد فقط. نفّذ تجارب جافة لطقوس المفاتيح وافحص القطع الفعلية الناتجة، بما فيها كائن HSM المسمى الذي ينتهي في الـ CSR.
  4. افحص شهاداتك الصادرة باستمرار، لا القوالب فقط. الشهادة هي الحقيقة الأرضية، وكل ما هو أعلى منها مجرد نية.

الشهادة هي الحقيقة الأرضية. كل ما يسبقها، من سكربتات وطقوس وعمليات تدقيق، مجرد نية.

ثمانية بتات هي كل ما يلزم

هناك شيء مطمئن بشكل غريب في كارثة لها سبب سخيف. خطأ في سكربت، ومفتاحان متشابهان الاسم على HSM، وإنسان يختار الخاطئ. لا دولة قومية، ولا تحليل تشفيري جديد، بل حلقة من مسلسل كوميدي مع فتيل مدته سبعة عشر شهراً. لكن السخف هو التحذير. إذا كانت أضعف حلقة في سلطة شهادات موثوقة عامة يمكن أن تكون بايتاً واحداً، فإن قوة PKI لديك لا تحددها اختيار المنحنى أو ميزانية HSM، بل يحددها ما إذا كان أحد، في أي مكان في خط المعالجة، قد اختبر المخرجات فعلاً.

قام مزودو المتصفحات بدورهم خلال ساعات. والباقي علينا: دقّق توليد مفاتيحك، وشغّل الفحوصات الرخيصة، وحدّث كل حزمة CA تصل إليها، وعزل الأجهزة التي لا تستطيع تحديثها. وتوقف عن افتراض أن أحداً آخر تحقق من الأساسيات. في الأمن الحساس، هذا هو أغلى افتراض على الإطلاق.