في المقالات السابقة في السلسلة ، ناقشنا أمان الذاكرة وسلامة الخيط في Rust. في هذه المقالة الأخيرة ، سننظر في الآثار المترتبة على تطبيق Rust حقيقي باستخدام مشروع Quantum CSS .يطبق مشغل CSS قواعد CSS على الصفحة. هذه عملية تنازلي تنحدر من شجرة DOM ، بعد حساب CSS الأصل ، يمكن حساب الأنماط الفرعية بشكل مستقل: مثالية للحوسبة المتوازية. بحلول عام 2017 ، قامت موزيلا بمحاولتين لموازنة نظام الأناقة باستخدام C ++. كلاهما فشل.
بدأ تطوير CSS الكم لزيادة الإنتاجية. تحسين الأمن هو مجرد تأثير جانبي جيد.
هناك صلة معينة بين حماية الذاكرة وأخطاء أمن المعلومات. لذلك ، توقعنا أن يؤدي استخدام Rust إلى تقليل سطح الهجوم في Firefox. ستبحث هذه المقالة في نقاط الضعف المحتملة التي تم تحديدها في محرك CSS منذ الإصدار الأولي من Firefox في عام 2002. ثم انظر إلى ما يمكن وما كان يمكن منعه من الصدأ.
طوال الوقت ، تم اكتشاف 69 خطأ أمني في مكون CSS في Firefox. إذا كان لدينا آلة زمنية واستطعنا أن نكتبها صدأ من البداية ، فإن أخطاء 51 (73.9 ٪) ستصبح مستحيلة. على الرغم من أن Rust يجعل كتابة الكود الجيد أسهل ، إلا أنه لا يوفر حماية مطلقة.
صدأ
الصدأ هي لغة برمجة النظام الحديثة التي هي آمنة للأنواع والذاكرة. كتأثير جانبي لهذه الضمانات الأمنية ، تعد برامج Rust آمنة أيضًا في وقت التجميع. وبالتالي ، الصدأ مناسب بشكل خاص لـ:
- معالجة آمنة للبيانات الواردة غير الموثوقة ؛
- التزامن لتحسين الأداء ؛
- دمج المكونات الفردية في قاعدة الشفرة الحالية.
ومع ذلك ، لا يعمل Rust على إصلاح بعض فئات الأخطاء بشكل صريح ، خاصةً أخطاء الأخطاء. في الواقع ، عندما أعاد مهندسونا كتابة Quantum CSS ، قاموا بطريق الخطأ بتكرار خطأ أمان خطير ، والذي تم إصلاحه مسبقًا في رمز C ++ ، قاموا بحذف
الخطأ bug fix
641731 ، والذي يسمح بتسريب التاريخ العالمي عبر SVG. تم إعادة تسجيل
الخطأ باسم
الخطأ 1420001 . يتم تصنيف تسرب محفوظات مثل ثغرة أمنية حرجة. كان الإصلاح الأولي بمثابة فحص إضافي لمعرفة ما إذا كان مستند SVG صورة. لسوء الحظ ، تم فقد هذا الاختيار عند إعادة كتابة الكود.
على الرغم من أن الاختبارات الآلية يجب أن تجد انتهاكات للقاعدة
:visited
مثل هذا ، إلا أنها في الواقع لم تجد هذا الخطأ. لتسريع الاختبارات التلقائية ، قمنا بتعطيل الآلية التي اختبرت هذه الميزة مؤقتًا - الاختبارات ليست مفيدة بشكل خاص إذا لم يتم تنفيذها. يمكن تقليل خطر إعادة تنفيذ الأخطاء المنطقية عن طريق تغطية اختبار جيدة. ولكن لا يزال هناك خطر حدوث أخطاء منطقية جديدة.
عندما يصبح المطور مطلعا على Rust ، يصبح كوده أكثر أمانًا. على الرغم من أن Rust لا يمنع كل الثغرات المحتملة ، فإنه يعمل على إصلاح فئة كاملة من الأخطاء الأكثر خطورة.
أخطاء أمان CSS الكم
بشكل عام ، بشكل افتراضي ، يمنع Rust الأخطاء المتعلقة بالذاكرة والحدود والمتغيرات الفارغة / غير المهيأة وتجاوزات عدد صحيح. يبقى الخطأ غير القياسي المذكور أعلاه ممكنًا: يحدث عطل بسبب فشل تخصيص الذاكرة.
أخطاء الأمن حسب الفئة
- الذاكرة: 32
- الحدود: 12
- التنفيذ: 12
- خالية: 7
- تجاوز سعة المكدس: 3
- عدد صحيح تجاوز: 2
- أخرى: 1
في تحليلنا ، جميع الأخطاء مرتبطة بالأمان ، لكن 43 فقط حصلوا على تصنيف رسمي (تم تعيينه من قبل مهندسي الأمن في موزيلا بناءً على افتراضات مؤهلة حول "قابلية الاستغلال"). قد تشير الأخطاء العادية إلى الوظائف المفقودة أو إلى حدوث خلل ما ، مما لا يؤدي بالضرورة إلى تسرب البيانات أو تغيير السلوك. تتراوح أخطاء الأمان الرسمية بين الأهمية المنخفضة (في حالة وجود قيود قوية على سطح الهجوم) إلى الضعف الشديد (قد تسمح للمهاجم بتشغيل تعليمات برمجية عشوائية على النظام الأساسي للمستخدم).
غالبًا ما يتم تصنيف الثغرات في الذاكرة على أنها مشكلات أمنية خطيرة. من بين 34 قضية حرجة / خطيرة ، 32 منها تتعلق بالذاكرة.
توزيع شدة الأخطاء الأمنية
- المجموع: 70
- أخطاء الأمن: 43
- حرجة / خطيرة: 34
- الصدأ الثابت: 32
مقارنة الصدأ و C ++
علة 955913 - تجاوز سعة المخزن المؤقت الكومة في الدالة
GetCustomPropertyNameAt
. استخدم الكود المتغير الخاطئ للفهرسة ، مما أدى إلى تفسير الذاكرة بعد نهاية المصفوفة. قد يتسبب هذا في حدوث عطل عند الوصول إلى مؤشر غير صحيح أو نسخ الذاكرة إلى سلسلة يتم تمريرها إلى مكون آخر.
يتم تخزين ترتيب جميع
خصائص CSS (بما في ذلك العرف ، أي العرف) في صفيف
mOrder
. يتم تمثيل كل عنصر إما بقيمة خاصية CSS ، أو في حالة الخصائص المخصصة ، القيمة التي تبدأ بـ
eCSSProperty_COUNT
(العدد الإجمالي لخصائص CSS غير المخصصة). للحصول على اسم الخصائص المخصصة ، تحتاج أولاً إلى الحصول على القيمة من
mOrder
، ثم الوصول إلى الاسم في الفهرس المقابل لصفيف
mVariableOrder
، الذي يخزن أسماء الخصائص المخصصة بالترتيب.
الضعيف رمز C ++:
void GetCustomPropertyNameAt(uint32_t aIndex, nsAString& aResult) const { MOZ_ASSERT(mOrder[aIndex] >= eCSSProperty_COUNT); aResult.Truncate(); aResult.AppendLiteral("var-"); aResult.Append(mVariableOrder[aIndex]);
المشكلة تحدث على السطر 6 عند استخدام
aIndex
للوصول إلى عنصر صفيف
mVariableOrder
. الحقيقة هي أنه يجب استخدام
mOrder
مع صفيف
mOrder
، وليس
mVariableOrder
. العنصر المقابل للخاصية المخصصة الممثلة في
mOrder
في
mOrder
هو في الواقع
mOrder[aIndex] - eCSSProperty_COUNT
.
تصحيح رمز C ++:
void Get CustomPropertyNameAt(uint32_t aIndex, nsAString& aResult) const { MOZ_ASSERT(mOrder[aIndex] >= eCSSProperty_COUNT); uint32_t variableIndex = mOrder[aIndex] - eCSSProperty_COUNT; aResult.Truncate(); aResult.AppendLiteral("var-"); aResult.Append(mVariableOrder[variableIndex]); }
المقابلة رمز الصدأ
على الرغم من أن Rust يشبه إلى حد ما C ++ ، فإنه يستخدم التجريدات الأخرى وهياكل البيانات. سيكون رمز الصدأ مختلفًا تمامًا عن C ++ (انظر أدناه لمزيد من التفاصيل). أولاً ، دعونا نلقي نظرة على ما يحدث إذا تم ترجمة الشفرة الضعيفة حرفيًا قدر الإمكان:
fn GetCustomPropertyNameAt(&self, aIndex: usize) -> String { assert!(self.mOrder[aIndex] >= self.eCSSProperty_COUNT); let mut result = "var-".to_string(); result += &self.mVariableOrder[aIndex]; result }
سوف يقبل برنامج التحويل البرمجي Rust هذا الرمز لأنه لا يمكن تحديد طول المتجهات قبل التنفيذ. على عكس المصفوفات ، التي يجب أن يكون طولها معروفًا ، فإن
لنوع Vec in Rust
حجمًا ديناميكيًا. ومع ذلك ، تم التحقق من الحدود في تطبيق متجه المكتبة القياسي. في حالة ظهور فهرس غير صالح ، يتم إنهاء البرنامج فورًا بطريقة خاضعة للرقابة ، مما يمنع أي وصول غير مصرح به.
يستخدم
الكود الحقيقي لـ CSS لـ Quantum بنية بيانات مختلفة جدًا ، لذلك لا يوجد ما يعادلها بالضبط. على سبيل المثال ، نستخدم هياكل البيانات المدمجة القوية في Rust لتوحيد الترتيب وأسماء الممتلكات. هذا يلغي الحاجة إلى الحفاظ على صفيفتين مستقلتين. تعمل هياكل بيانات الصدأ أيضًا على تحسين تغليف البيانات وتقليل احتمال حدوث مثل هذه الأخطاء المنطقية. نظرًا لأن الشفرة يجب أن تتفاعل مع رمز C ++ في أجزاء أخرى من المستعرض ، فإن وظيفة
GetCustomPropertyNameAt
الجديدة
GetCustomPropertyNameAt
تبدو كأنها تعليمة برمجية Rust. لكنه لا يزال يعطي جميع ضمانات الأمن ، مع توفير مجموعة أكثر قابلية للفهم من البيانات الأساسية.
د
نظرًا لأن الثغرات الأمنية ترتبط غالبًا بانتهاكات أمان الذاكرة ، يجب على كود الصدأ تقليل عدد
CVE الحرجة بشكل
كبير . ولكن حتى الصدأ ليست مثالية. لا يزال يتعين على المطورين تتبع أخطاء التصحيح وهجمات تسرب البيانات. لا يزال دعم المكتبات الآمنة يتطلب مراجعة الشفرات والاختبارات والاندماج.
لا يمكن للمجمعين التقاط جميع أخطاء المبرمج. ومع ذلك ، يزيل Rust عبء أمان الذاكرة الخاص بنا ، مما يسمح لنا بالتركيز على الصواب المنطقي للرمز.