في 3 كانون الثاني (يناير) 2018 ،
كشف Google Project Zero وآخرون
عن الثلاثة الأولى من فئة جديدة من الثغرات الأمنية التي تؤثر على معالجات التنفيذ المضاربة. كانت تسمى
شبح (1 و 2)
والانهيار . باستخدام آليات
تنفيذ وحدة المعالجة المركزية
المضاربة ، يمكن للمهاجم أن يتفقد مؤقتًا كل من اختبارات أمان البرامج الصريحة والضمنية التي تمنع البرامج من قراءة البيانات التي يتعذر الوصول إليها في الذاكرة. في حين تم تصميم تنفيذ المضاربة كجزء من البنية الدقيقة ، غير مرئية على المستوى المعماري ، يمكن للبرامج المصممة بعناية قراءة المعلومات التي يتعذر الوصول إليها في كتلة المضاربة والكشف عنها من خلال القنوات الجانبية ، مثل وقت تنفيذ جزء البرنامج.
عندما تبين أن هجمات Specter ممكنة باستخدام JavaScript ، شارك فريق V8 في حل المشكلة. لقد شكلنا فريقًا للاستجابة لحالات الطوارئ وعملنا عن كثب مع فرق Google الأخرى وشركاء المتصفح الآخرين وشركاء الأجهزة. جنبا إلى جنب معهم ، أجرينا بشكل استباقي كل من البحوث الهجومية (تصميم وحدات الهجوم لإثبات المفهوم) والدفاعية (تخفيف الهجمات المحتملة).
يتكون هجوم سبيكتر من جزأين:
- تسرب البيانات التي يتعذر الوصول إليها بطريقة أخرى في الحالة الكامنة لوحدة المعالجة المركزية . تستخدم كل هجمات Specter المعروفة تكهنات لنقل بتات من البيانات التي يتعذر الوصول إليها إلى ذاكرات التخزين المؤقت لوحدة المعالجة المركزية.
- استعادة حالة مخفية لاستعادة البيانات التي يتعذر الوصول إليها. لهذا ، يحتاج المهاجم إلى مشاهدة بدقة كافية. (دقة منخفضة بشكل مدهش ، خاصة مع طرق مثل عتبة الحافة - مقارنة مع حد على طول مخطط تفصيلي محدد)
نظريا ، سيكون كافيا لمنع أي من عنصري الهجوم. نظرًا لأننا لا نعرف كيفية حظر أي منها تمامًا ، فقد قمنا بتطوير ونشر عمليات التخفيف التي تقلل إلى حد كبير كمية المعلومات التي تتسرب إلى ذاكرة التخزين المؤقت لوحدات المعالجة المركزية والتخفيفات التي تجعل من الصعب استرداد حالة مخفية.
مؤقتات عالية الدقة
تغيرات الحالة الصغيرة التي تبقى بعد تنفيذ المضاربة ينتج عنها اختلافات زمنية صغيرة ، وصغيرة بشكل شبه مستحيل تقريبًا ، في حدود المليار من الثانية. للكشف المباشر عن مثل هذه الاختلافات الفردية ، يحتاج المهاجم إلى جهاز توقيت عالي الدقة. تقدم المعالجات مثل هذه المؤقتات ، لكن منصة الويب لا تحددها. كان أدق الموقت على منصة الويب
performance.now()
دقة عدة ميكروثانية ، والتي كانت تعتبر في البداية غير مناسبة لهذا الغرض. ومع ذلك ، قبل عامين ، نشرت مجموعة بحثية متخصصة في هجمات الهندسة المجهرية
مقالة عن أجهزة ضبط الوقت على منصة على شبكة الإنترنت. وخلصوا إلى أن الذاكرة المشتركة القابلة للتبديل المتزامنة وأساليب الاسترداد القرار المختلفة تسمح بإنشاء أجهزة ضبط وقت دقة أعلى ، حتى nanosecond. تكون أجهزة ضبط الوقت هذه دقيقة بدرجة كافية للكشف عن عدد الزيارات الفردية المفقودة في ذاكرة التخزين المؤقت L1. هو الذي يستخدم عادة لالتقاط المعلومات في هجمات سبيكتر.
حماية الموقت
لتعطيل القدرة على اكتشاف الاختلافات الصغيرة في الوقت المناسب ، اختار مطورو المتصفح طريقة متعددة الأطراف. في جميع المتصفحات ، تم تقليل دقة
performance.now()
(في Chrome من 5 ميكروثانية إلى 100) وتم تقديم ارتعاش عشوائي لمنع استعادة الدقة. بعد التشاور بين مطوري جميع المتصفحات ، قررنا معًا اتخاذ خطوة غير مسبوقة: على الفور وبشكل رجعي قم بتعطيل
SharedArrayBuffer
API في جميع المتصفحات لمنع إنشاء مؤقت nanosecond.
تقوية
في بداية أبحاثنا الهجومية ، أصبح من الواضح أن عمليات تخفيف التوقيت وحدها لا تكفي. أحد الأسباب هو أن المهاجم يمكنه ببساطة تشغيل الكود الخاص به مرارًا وتكرارًا بحيث يكون الفارق الزمني التراكمي أكثر من مجرد ضربة واحدة أو فقدان ذاكرة التخزين المؤقت. تمكنا من بناء "أدوات ذكية" يمكن الاعتماد عليها والتي تستخدم العديد من خطوط ذاكرة التخزين المؤقت في وقت واحد ، حتى سعة ذاكرة التخزين المؤقت بأكملها ، مما يعطي فرقًا زمنيًا يصل إلى 600 ميكروثانية. في وقت لاحق ، اكتشفنا طرق تضخيم عشوائية لا تقتصر على سعة ذاكرة التخزين المؤقت. تعتمد طرق التضخيم هذه على محاولات متكررة لقراءة البيانات السرية.
حماية جيت
لقراءة البيانات التي يتعذر الوصول إليها باستخدام Specter ، يجبر المهاجم وحدة المعالجة المركزية على تنفيذ التعليمات البرمجية التي تقرأ عادة البيانات التي يتعذر الوصول إليها وتضعها في ذاكرة التخزين المؤقت. يمكن اعتبار الحماية من الجانبين:
- منع تنفيذ كود المضاربة.
- منع قراءة البيانات التي يتعذر الوصول إليها من خط أنابيب المضاربة.
لقد
LFENCE
الخيار الأول عن طريق إدخال الإرشادات الموصى بها لمنع المضاربة ، مثل Intel
LFENCE
من كل فرع من فروع الشرطية الحرجة واستخدام
retololins للفروع غير المباشرة. لسوء الحظ ، تؤدي عمليات التخفيف الشديدة هذه إلى تقليل الإنتاجية بدرجة كبيرة (تباطؤ بمعدل 2-3 أضعاف على معيار أوكتان). بدلاً من ذلك ، اتخذنا الطريقة الثانية عن طريق إدخال تسلسلات تخفيف تمنع قراءة البيانات الحساسة بسبب تكهنات غير صحيحة. اسمحوا لي أن أوضح الأسلوب باستخدام الكود التالي:
if (condition) { return a[i]; }
للبساطة ، نفترض هذا الشرط
0
أو
1
. تكون الشفرة أعلاه عرضة للضعف إذا كانت وحدة المعالجة المركزية تقرأ من
a[i]
عندما
i
خارج النطاق ، مع الوصول إلى البيانات التي يتعذر الوصول إليها عادةً. ملاحظة مهمة هي أنه في هذه الحالة ، تحاول المضاربة قراءة
a[i]
عندما يكون الشرط
0
. يقوم برنامج التخفيف الخاص بنا بإعادة كتابة هذا البرنامج بحيث يتصرف تمامًا مثل البرنامج الأصلي ، لكنه لا يسمح بتسريب أي بيانات محملة بشكل مضاربي.
نحن نحتفظ بسجل وحدة المعالجة المركزية واحد ، والذي نسميه "السم" ، لتتبع ما إذا كان رمز ينفذ في فرع يساء تفسيرها. يتم دعم سجل السموم في جميع الفروع ومكالمات الشفرة التي تم إنشاؤها ، لذا فإن أي فرع مترجم بطريقة غير صحيحة يتسبب في أن يصبح سجل السموم صفرًا. ثم نقيس جميع عمليات الوصول إلى الذاكرة بحيث تحجب نتيجة جميع التنزيلات دون قيد أو شرط بالقيمة الحالية لسجل السم. هذا لا يمنع المعالج من التنبؤ (أو إساءة تفسير) الفروع ، لكنه يدمر المعلومات (التي يحتمل أن تكون خارج الحدود) من القيم المحملة بسبب الفروع التي تم تفسيرها بشكل غير صحيح. يظهر رمز الأداة أدناه (صفيف من الأرقام).
let poison = 1;
لا يؤثر الرمز الإضافي على السلوك العادي (المحدد من قِبل الهندسة المعمارية) للبرنامج. يؤثر فقط على الحالة المعمارية الدقيقة عند العمل على وحدة المعالجة المركزية مع تنفيذ المضاربة. إذا كنت تستخدم برنامجًا على مستوى الكود المصدري ، فيمكن أن تؤدي التحسينات المتقدمة في برامج الترجمة الحديثة إلى إزالة هذه الأجهزة. في V8 ، نمنع المترجم من إزالة التخفيفات عن طريق إدخالها في مرحلة متأخرة جدًا من التجميع.
نستخدم أيضًا تقنية التسمم هذه لمنع تسربات من الفروع غير المباشرة في حلقة البايت كود للمترجم وفي تسلسل استدعاءات وظائف JavaScript. في المترجم الشفوي ، قمنا بتعيين السم على
0
إذا لم يتطابق معالج bytecode (على سبيل المثال ، تسلسل رمز الجهاز الذي يفسر رمزًا فرعيًا واحدًا) مع الرمز الفرعي الحالي. بالنسبة إلى مكالمات JavaScript ، نقوم بتمرير الوظيفة الهدف كمعلمة (في السجل) ونضبط السم على
0
في بداية كل وظيفة إذا كانت الوظيفة الهدف الواردة لا تتطابق مع الوظيفة الحالية. مع هذا التليين ، نرى تباطؤًا أقل من 20٪ في مؤشر أوكتان.
يعد التخفيف لـ WebAssembly أبسط ، نظرًا لأن الفحص الأمني الرئيسي هو التأكد من أن الوصول إلى الذاكرة يقع ضمن الحدود. بالنسبة إلى الأنظمة الأساسية ذات 32 بت ، بالإضافة إلى عمليات التحقق من الحدود المعتادة ، نملأ كل الذاكرة بالقدرة التالية لقمتين ونخفي أي بتات أعلى من فهرس ذاكرة المستخدم دون قيد أو شرط. لا تحتاج الأنظمة الأساسية 64 بت إلى مثل هذا التخفيف ، حيث أن التطبيق يستخدم حماية الذاكرة الظاهرية لفحص الحدود. لقد جربنا تجميع بيانات التبديل / الحالة إلى رمز بحث ثنائي بدلاً من استخدام فرع غير مباشر محتمل أن يكون ضعيفًا ، لكنه مكلف للغاية بالنسبة لبعض أعباء العمل. المكالمات غير المباشرة محمية بواسطة retololins.
حماية البرمجيات - غير موثوق بها
لحسن الحظ أو لسوء الحظ ، تقدمت أبحاثنا الهجومية بشكل أسرع من الدفاعية ، ووجدنا بسرعة أنه من المستحيل تخفيف جميع التسريبات المحتملة برمجيًا خلال هجمات Specter. هناك عدة أسباب لذلك. أولاً ، الجهود الهندسية لمكافحة Specter غير متناسبة مع مستوى التهديد. في الإصدار الثامن ، نواجه العديد من المخاطر الأمنية الأخرى الأسوأ ، من القراءة المباشرة للحدود الخارجية بسبب الأخطاء الشائعة (التي هي أسرع وأسهل من Specter) ، والكتابة خارج الحدود (وهذا مستحيل مع Specter والأسوأ) وإمكانية التحكم عن بعد تنفيذ التعليمات البرمجية (مستحيل مع Specter والأسوأ بكثير). ثانياً ، إن إجراءات التخفيف المتزايدة التعقيد التي قمنا بتطويرها وتنفيذها تحمل تعقيدًا كبيرًا ، وهو التزام تقني ويمكن أن يزيد فعليًا سطح الهجوم ونفقات الأداء. ثالثًا ، يعد اختبار تسريبات التسريبات المعمارية الصغرى والحفاظ عليها أكثر صعوبة من تصميم الأدوات نفسها للهجوم ، حيث يصعب التأكد من أن عمليات التخفيف تستمر في العمل بالطريقة التي تم تصميمها بها. مرة واحدة على الأقل ، تم التخفيف بشكل فعال عمليات التخفيف الهامة بواسطة تحسينات المحول البرمجي اللاحقة. رابعا ، وجدنا أن التخفيف الفعال لبعض خيارات Specter ، وخاصة الخيار 4 ، غير ممكن ببساطة في البرنامج ، حتى بعد الجهود البطولية لشركائنا في Apple للتعامل مع المشكلة في برنامج التحويل البرمجي JIT الخاص بهم.
عزل الموقع
أدى بحثنا إلى الاستنتاج: من حيث المبدأ ، يمكن لرمز غير موثوق به قراءة مساحة العنوان بالكامل لعملية باستخدام Specter والقنوات الجانبية. تقلل عمليات تخفيف البرامج من فعالية العديد من الأدوات الذكية المحتملة ، ولكنها ليست فعالة أو شاملة. التدبير الفعال الوحيد هو نقل البيانات الحساسة خارج مساحة عنوان العملية. لحسن الحظ ، يحاول Chrome لسنوات عديدة فصل المواقع في عمليات مختلفة من أجل تقليل سطح الهجوم بسبب نقاط الضعف الشائعة. أثمرت هذه الاستثمارات ، وبحلول مايو 2018 وصلنا إلى مرحلة الاستعداد ووسّعنا
عزلة المواقع على الحد الأقصى لعدد المنصات. وبالتالي ، لم يعد نموذج أمان Chrome يفترض خصوصية اللغة أثناء عملية التجسيد.
لقد قطع Specter شوطًا طويلًا وشدد على مزايا تعاون المطور في الصناعة والأوساط الأكاديمية. حتى الآن ، القبعات البيضاء تفوق القبعات السوداء. ما زلنا لا نعرف عن أي هجوم حقيقي واحد ، باستثناء المجربين الفضائيين والباحثين المحترفين الذين يقومون بتطوير أدوات لإثبات هذا المفهوم. تستمر المتغيرات الجديدة من هذه الثغرات في الظهور وسيستمر هذا لبعض الوقت. نواصل مراقبة هذه التهديدات ونأخذها على محمل الجد.
مثل العديد من المبرمجين ، اعتقدنا أيضًا أن اللغات الآمنة توفر الحد الصحيح للتجريد ، وتمنع البرامج المكتوبة جيدًا من قراءة الذاكرة التعسفية. إنه لأمر محزن أن تبين أن هذا خطأ - فهذا الضمان لا يتوافق مع معدات اليوم. بالطبع ، ما زلنا نعتقد أن اللغات الآمنة تتمتع بمزيد من المزايا الهندسية ، والمستقبل يكمن فيها ، لكن ... على المعدات الحالية فإنها تتسرب قليلاً.
يمكن للقراء المهتمين أن يتعمقوا في الموضوع ويحصلوا على معلومات أكثر تفصيلاً في مقالتنا
العلمية .