استخدام eval في إضافات Chrome

يفرض نظام إضافات Chrome سياسة أمان المحتوى (CSP) التلقائية الصارمة إلى حدٍ ما. قيود السياسة واضحة ومباشرة: يجب نقل النص البرمجي خارج السطر إلى مجموعة منفصلة يجب تحويل ملفات JavaScript ومعالِجات الأحداث المضمّنة لاستخدام addEventListener، كما أنّ السمة eval() هي غير مفعّل. تفرض تطبيقات Chrome سياسة أكثر صرامة، ونحن سعداء جدًا بميزات الأمان التي تقدّمها هذه السياسات.

ومع ذلك، فإننا ندرك أن مجموعة متنوعة من المكتبات تستخدم التركيبات eval() والتركيبات المشابهة لـ eval مثل. new Function() لتحسين الأداء وسهولة التعبير. تكون مكتبات النماذج معرضة بشكل خاص لهذا النمط من التنفيذ. على الرغم من أنّ بعض الإطارات (مثل Angular.js) تتيح استخدام CSP بدون أي إعدادات، لم يتم تعديل العديد من الإطارات الشائعة حتى الآن لتتوافق مع eval في الإضافات. لذلك، تبيّن أنّ إزالة إمكانية استخدام هذه الوظيفة أكثر إزعاجًا للمطوّرين مما كان متوقّعًا.

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

لماذا نستخدم وضع "الصندوق الرمّل"؟

يُعد eval خطيرًا داخل إضافة لأن الرمز البرمجي الذي ينفّذه لديه إمكانية الوصول إلى كل شيء في ذات الأذونات العالية للإضافة. يتوفر عدد كبير من واجهات برمجة تطبيقات chrome.* الفعّالة التي يمكن تؤثر بشدة في أمان المستخدم وخصوصيته؛ والاستخراج البسيط للبيانات هو أقل ما يقلقنا. يتمثل الحلّ المُقدَّم في مساحة محاكاة يمكن فيها لـ eval تنفيذ رمز بدون الوصول إلى data الإضافة أو واجهات برمجة التطبيقات العالية القيمة للإضافة. ما مِن بيانات أو واجهات برمجة تطبيقات.

ونحقق ذلك من خلال إدراج ملفات HTML محددة داخل حزمة الإضافات باعتبارها في وضع الحماية. عند تحميل صفحة في وضع الحماية، سيتم نقلها إلى مصدر فريد، وسيتم رفضها. الوصول إلى واجهات برمجة تطبيقات chrome.*. إذا قمنا بتحميل الصفحة التي تم وضع الحماية لها في الإضافة عبر iframe، فيمكننا وتمريرها، والسماح لها بالتصرف بشأن هذه الرسائل بطريقة ما، ثم الانتظار حتى ترسل إلينا الرسالة نتيجته. تمنحنا آلية المراسلة البسيطة هذه كل ما نحتاج إليه لتضمين المحتوى الذي يعتمد على eval بأمان. في سير عمل الإضافة.

إنشاء مساحة محاكاة واستخدامها

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

إدراج الملفات في البيان

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

{
  ...,
  "sandbox": {
     "pages": ["sandbox.html"]
  },
  ...
}

تحميل الملف في وضع الحماية

لنتمكّن من تنفيذ إجراء مثير للاهتمام باستخدام الملف المثبّت في وضع الحماية، علينا تحميله في سياق فيمكن معالجتها من خلال رمز الإضافة. في ما يلي، تم تحميل sandbox.html في صفحة الحدث (eventpage.html) للإضافة من خلال iframe. يحتوي eventpage.js على رمز ترسل رسالة إلى وضع الحماية كلما تم النقر على إجراء المتصفح من خلال العثور على iframe في الصفحة، مع تنفيذ الطريقة postMessage على contentWindow. الرسالة عبارة عن كائن تحتوي على خاصيتين: context وcommand. سنتناول كلتا المسألتين بعد قليل.

chrome.browserAction.onClicked.addListener(function() {
 var iframe = document.getElementById('theFrame');
 var message = {
   command: 'render',
   context: {thing: 'world'}
 };
 iframe.contentWindow.postMessage(message, '*');
});
للحصول على معلومات عامة عن postMessage API، يمكنك الاطّلاع على مستندات postMessage حول MDN . إنه كامل تمامًا وتستحق القراءة. يُرجى العلم أنّه لا يمكن نقل البيانات ذهاباً وإيابًا إلا إذا كانت قابلة للتسلسل. الدوال، على سبيل المثال، ليست كذلك.

تنفيذ إجراءات خطيرة

عند تحميل sandbox.html، يتم تحميل مكتبة "المقابس" وإنشاء محتوى مضمّن وتجميعه. قالب دقيق بالطريقة التي تقترح بها المقاود:

<script src="handlebars-1.0.0.beta.6.js"></script>
<script id="hello-world-template" type="text/x-handlebars-template">
  <div class="entry">
    <h1>Hello, !</h1>
  </div>
</script>
<script>
  var templates = [];
  var source = document.getElementById('hello-world-template').innerHTML;
  templates['hello'] = Handlebars.compile(source);
</script>

هذا الإجراء ناجح. على الرغم من أنّ Handlebars.compile ينتهي باستخدام new Function، تعمل الأمور على النحو المتوقّع تمامًا، وينتهي بنا المطاف بنموذج مجمّع في templates['hello'].

تمرير النتيجة مرة أخرى

سنجعل هذا النموذج متاحًا للاستخدام من خلال إعداد أداة معالجة رسائل تقبل الأوامر. من صفحة الحدث. سنستخدم command الذي تم تمريره لتحديد ما يجب فعله (يمكنك تخيّل تنفيذ ما هو أكثر من مجرد العرض، وربما إنشاء قوالب؟ Perhaps managing them in some way?), and the context will be passed into the template directly for rendering. سيتمّ تمرير محتوى HTML المعروض إلى صفحة الحدث لكي تتمكّن الإضافة من إجراء إجراء مفيد به لاحقًا:

<script>
  window.addEventListener('message', function(event) {
    var command = event.data.command;
    var name = event.data.name || 'hello';
    switch(command) {
      case 'render':
        event.source.postMessage({
          name: name,
          html: templates[name](event.data.context)
        }, event.origin);
        break;

      // case 'somethingElse':
      //   ...
    }
  });
</script>

بالعودة إلى صفحة الحدث، سنتلقى هذه الرسالة ونتخذ إجراءً مثيرًا باستخدام html البيانات التي مررنا بها. في هذه الحالة، سنردّدها عبر إشعار على سطح المكتب، ولكن من الممكن تمامًا استخدام كود HTML هذا بأمان كجزء من واجهة المستخدم للإضافة. إدراجه عبر لا يُشكّل innerHTML خطرًا أمنيًا كبيرًا، حتى لو كان اختراقًا كاملاً في وضع الحماية من خلال بعض الهجمات الذكية، لن يتم إدخال محتوى نص برمجي أو مكوّن إضافي خطير في سياق الإضافة ذات الأذونات العالية

تجعل هذه الآلية إنشاء النماذج أمرًا سهلاً، ولكنّها لا تقتصر بالطبع على ذلك. يمكن وضع أي رمز برمجي في بيئة الحماية في حال لم يعمل بشكل تلقائي بموجب سياسة صارمة لأمان المحتوى. وفي الواقع، من المفيد غالبًا وضع مكونات الإضافات التي ستتم إدارتها بشكل صحيح في بيئة الحماية من أجل حصر كل جزء من برنامجك بأصغر مجموعة من الأذونات اللازمة لتنفيذه بشكل سليم. العرض التقديمي حول كتابة تطبيقات الويب الآمنة وإضافات Chrome من Google ويقدم مؤتمر I/O 2012 بعض الأمثلة الجيدة لهذه التقنية على أرض الواقع، وتستحق 56 دقيقة من الوقت.