الأمان
ينقسم سطح الهجوم في أي متصفّح إلى قسمين: المحرّك الذي لم نكتبه، والغلاف الذي كتبناه. ويختلف سلوك الاثنين اختلافًا كبيرًا، لذلك نشرحهما كلًّا على حدة. والثغرات المعروفة في هذا الإصدار في آخر الصفحة.
المحرّك: Chromium وV8 وSkia
خلال عام 2026 أُغلقت في Chrome عشرات الثغرات المتعلّقة بأمان الذاكرة، منها ستّ ثغرات يوم صفر استُغلّت فعليًا في البرّية. نحن لا نكتب هذا الكود ولا نستطيع إصلاحه؛ والدفاع الوحيد هنا هو إبقاء المحرّك محدّثًا.
لذلك فقاعدتنا واضحة: لا يصدر Girginos Browser على إصدار من Electron انتهى عمره. فـ Electron لا يدعم إلا آخر ثلاثة إصدارات رئيسية، ويُراجَع تثبيت الإصدار قبل كل إطلاق. ونستخدم حاليًا Electron 44.2.0 مع Chromium 152.0.7977.76.
الغلاف: الكود الذي كتبناه
هذه هي القرارات المعمارية في جانب الغلاف:
- كل علامة تبويب هي WebContentsView منفصلة. ومحتوى الصفحة يعمل بـ sandbox: true وcontextIsolation: true وnodeIntegration: false، ولا يحصل على preload.
- ونافذة الواجهة تعمل هي أيضًا في وضع معزول وتشترك مع علامات التبويب في الجلسة نفسها؛ وبذلك تمرّ طلبات الواجهة نفسها عبر الحاجب وتحمل ترويسات DNT.
- لا تُقبل قنوات IPC إلا من الإطار الرئيسي لنافذة الواجهة. وتمرّ عمليات كتابة الإعدادات بتحقّق من المفتاح والنوع.
- تُعنوَن التنزيلات بمعرّف؛ ولا يُفتح أبدًا مسار ملفّ خام قادم من الواجهة.
- لا يمكن أن يكون التنقّل الصادر عن الصفحة إلا http(s) وview-source:http(s). أمّا file: وchrome: فلا يُفتحان إلا إذا كتبهما المستخدم بنفسه في شريط العنوان.
- والتسليم إلى تطبيق خارجي محصور بقائمة مخطّطات ضيّقة: mailto: وtel: وsms: وmagnet: وftp(s): وwebcal:. ولا يُفتح إلا مربّع تأكيد واحد في المرّة.
- والمصادر المُعتِمة، أي التي تكون origin لديها null مثل data: وabout:، تُرفض دائمًا في طلبات الأذونات.
- والتدقيق الإملائي معطّل، لأن Chromium ينزّل ملفّات القاموس من خادم تابع لـ Google.
- وتُكتب البيانات كتابة ذرّية عبر ملفّ مؤقّت ثم إعادة تسمية.
متّجهات الهجوم والتدابير المضادّة
| الصنف | مثال | التدبير المضادّ |
|---|---|---|
| انتحال شريط العنوان | RLO/bidi, CR-LF, NUL, bank.com@evil.com, حشو بمسافات، تشابه حروف IDN | تبقى المحارف غير المرئية والمسافات مرمّزة، وتُخفى بيانات الاعتماد، ويُعرض punycode |
| إخفاء اسم النطاق | accounts.google.com.giris.evil.com | يُكتب النطاق القابل للتسجيل بلون غامق والباقي باهتًا |
| انتحال صفحة داخلية | newtab.html, نسخة منزَّلة | يُشترط تطابق العنوان كاملًا؛ ولا يجري بحث عن سلسلة جزئية |
| انتحال الواجهة في وضع ملء الشاشة | تنتقل الصفحة إلى ملء الشاشة وترسم شريط أدوات مزيّفًا | لا يُوسَّع عرض الصفحة فوق الغلاف أبدًا |
| الإفلات من المخطّط | file:, chrome:, blob:, view-source:file: | لا يُسمح في التنقّل الصادر عن الصفحة إلا بـ http(s) |
| استدعاء تطبيق خارجي | ms-msdt:, search-ms:, ms-appinstaller: | قائمة سماح ضيّقة ومربّع تأكيد واحد |
| حيل أسماء التنزيلات | evil.exe / evil.exe., نقطة أو مسافة في النهاية، امتداد مخفيّ بـ RLO | تطبيع الاسم قبل فحص الامتداد؛ والقرار يُتَّخذ وفق الاسم الحقيقي على القرص |
| التحايل على الحاجب | izleyici.com., نقطة في النهاية | تطبيع اسم المضيف |
سلسلة التحديث الموقّعة
يفترض نموذج التهديد أن خادم التحديث قد يكون مخترَقًا بالفعل. وتسير الخطوات هكذا:
- يُجلب البيان الموقّع وملفّ التوقيع المجاور له.
- يُتحقّق من التوقيع على البايتات الخام للبيان بمفتاح Ed25519 العام المضمَّن في التطبيق. وإن لم يجتز التحقّق فلا يُقرأ أي حقل.
- تُطبَّق بوّابات الإصدار: يُرفض التراجع إلى إصدار أقدم؛ ويُرفض البيان إذا تجاوز تاريخ انتهائه، وهذا في مواجهة هجوم يقدّم بيانًا قديمًا إلى الأبد فيجمّد التحديثات؛ ويُفرَض إصدار وسيط عند الحاجة؛ ويجب أن يكون عنوان التنزيل https.
- يجب أن يتطابق الإصدار وبصمة الحزمة اللذان وجدتهما أداة التنزيل تطابقًا تامًّا مع ما في البيان الموقّع.
- وبعد انتهاء التنزيل تُقارَن بصمة sha512 للحزمة بالبصمة الموقّعة مقارنةً بزمن ثابت.
- ولا يبدأ التثبيت إلا بموافقة المستخدم.
إذا أخفقت أي خطوة فلا يجري التحديث. والمفتاح الخاص لا يوجد على الخادم أبدًا؛ فحتى لو اختُرق الخادم، لا يستطيع المهاجم إنتاج بيان صالح.
الاختبارات
يعمل 118 اختبار وحدة و73 اختبار انحدار لمتّجهات الهجوم و46 اختبارًا للتحقّق من التحديث، ويُختبر كذلك عقد IPC وDOM بين الواجهة والعملية الرئيسية اختبارًا منفصلًا. وإلى جانب ذلك تُشغَّل قبل الإطلاق وبعده نصوص تحقّق من طرف إلى طرف على المخرجات الحقيقية وعلى الخادم الحيّ.
الثغرات المعروفة
ما يلي ناقص في 0.1.0. وإخفاؤه يجعل المنتج يبدو أكثر أمانًا ممّا هو عليه، لذلك نكتبه صراحةً.
- لا يوجد Mark-of-the-Web
- لا يُكتب Zone.Identifier على الملفّات المنزَّلة، ولذلك لا يتدخّل Windows SmartScreen في شأنها. للمتصفّح مربّع تحذير خاصّ به، لكن طبقة نظام التشغيل غائبة.
- لا توجد شهادة توقيع برمجي
- لا يمكن التحقّق من التوقيع البرمجي لحزمة التثبيت. والبيان الموقّع يسدّ هذا في التحديثات، لكن التثبيت الأول يبقى مكشوفًا.
- لا توجد Public Suffix List
- على نطاقات الاستضافة مثل github.io، تشمل استثناءات المواقع وإبراز شريط العنوان نطاقًا أوسع ممّا ينبغي.
- أخطاء الشهادات تتبع سلوك Chromium الافتراضي
- لم تُكتب شاشة «تابع على أي حال» خاصّة بنا؛ وعند وجود شهادة خاطئة لا تُفتح الصفحة.
- الحجب على مستوى النطاق فقط
- لا تُلتقط المتتبّعات المخفيّة خلف سجلّات CNAME ولا الإعلانات المقدَّمة من الطرف الأول، ولا تُطبَّق فلاتر تجميلية.