Caputchin
فهم Caputchin

كيف يعزل Caputchin الألعاب

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

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

نموذج التهديد في سطر

تشغّل اللعبة JavaScript عشوائيًّا (وربما WebAssembly) يقدّمها طرف ثالث. هدف العزل إذن: تستطيع اللعبة الحوسبة والرسم، وتستطيع تسليم نتيجة إلى الأداة، لكنها لا تستطيع قراءة أو التأثير في أي شيء خارج إطارها. كل طبقة أدناه تخدم ذلك الهدف الواحد، وهي دفاع بالعمق، لا طبقة واحدة موثوقة بأنها مثالية.

الطبقة 1: إطار iframe معزول بأصل معتم

تعمل كل لعبة داخل <iframe> تبنيه الأداة بسمة sandbox دنيا عمدًا. الرمز الوحيد الممنوح هو allow-scripts، لأن اللعبة JavaScript ويجب أن تعمل. كل ما عداه محجوب، وأهمّ حذف هو allow-same-origin.

بدون allow-same-origin يعطي المتصفّح الإطار أصل null فريدًا. تلك الحقيقة الواحدة هي الحدّ الحامل:

  • لا تستطيع اللعبة قراءة DOM صفحتك، أو كوكيزها، أو localStorage، أو جلسة Caputchin، فهي مختومة في أصل قابل للرمي غريب عن أصلك.
  • ولأن الإطار لا يستطيع أيضًا التنقّل بنافذتك العليا، أو فتح نوافذ منبثقة، أو إرسال نماذج، أو إظهار حوارات أصلية (كل تلك القدرات رموز عزل لا يمنحها Caputchin)، فلا مسار من اللعبة عودةً إلى صفحتك.

تركيبة allow-scripts بدون allow-same-origin هي بيت القصيد كلّه: ينفّذ المتصفّح كود اللعبة لكنه يعامل الإطار كأصل غريب لا يلمس شيئًا من أصلك. لا يضيف Caputchin أبدًا allow-same-origin إلى إطار لعبة. (وكنتيجة، كل رسالة ترسلها اللعبة إلى الأداة تصل من أصل "null"، وهو ما تتوقّعه فحوص قناة الأداة، فأصل غير null سيشير بنفسه إلى عزل مُعَدّ خطأً.)

الطبقة 2: وثيقة الإطار تُبنى مضمَّنةً، لا تُجلَب

لا توجّه الأداة الإطار إلى صفحة بعيدة. تبني وثيقة HTML الكاملة للإطار مضمَّنةً (عبر srcdoc) وتسلّمها للإطار ذي الأصل null. تلك الوثيقة ضئيلة: وسم CSP صارم في meta (الطبقة التالية)، وإقلاع زمن تشغيل Caputchin صغير، ووسم <script> واحد يحمّل حزمة اللعبة.

هذه الآلية نفسها لمساري التسليم كليهما، ولا يختلف سوى رابط الحزمة:

مصدر اللعبةرابط الحزمة في الوثيقة المضمَّنة
المتجر (محلولة من المنصّة)رابط الحزمة المثبَّت والمجزَّأ بالسلامة الذي حلّه Caputchin عند التركيب.
مستضافة ذاتيًّا (game-src خاصتك)الرابط الذي قدّمته.

ولأن الوثيقة مؤلَّفة من الأداة لا اللعبة، لا تتحكّم اللعبة أبدًا بالـ CSP، أو زمن التشغيل، أو بنية الإطار، بل فقط بما تفعله حزمتها بعد تحميلها.

الطبقة 3: Subresource Integrity لألعاب المتجر

حين يقدّم Caputchin لعبة المتجر يثبّت الحزمة على نسخة غير قابلة للتغيير ويسجّل تجزئة تعمّية (SHA-384) منها. وسم <script> الذي يحمّل الحزمة يحمل تلك التجزئة كسمة integrity مع crossorigin="anonymous"، فيرفض المتصفّح نفسه تنفيذ الحزمة إن اختلف بايت واحد عمّا ثُبِّت. CDN مخترَق لا يستطيع استبدال كود مختلف؛ يفشل التحميل مغلقًا.

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

الطبقة 4: Content-Security-Policy مضمَّنة صارمة

تحمل الوثيقة المضمَّنة Content-Security-Policy ضيّقةً. رغم أن الإطار أصلًا بأصل null ومعزول، يقيّد الـ CSP أكثر ما يستطيع الكود المحمَّل فعله، يرفض كل شيء افتراضيًّا ويعيد منح الحدّ الأدنى فقط:

التوجيهالقيمةلماذا
default-src'none'ارفض كل ما لا يُسمَح به صراحةً أدناه.
script-srcتجزئة لزمن تشغيل Caputchin المضمَّن + أصل حزمة اللعبة + 'wasm-unsafe-eval'شغّل فقط إقلاع Caputchin بالضبط (مثبَّتًا بتجزئة sha256-، لا 'unsafe-inline') وحزمة اللعبة نفسها. 'wasm-unsafe-eval' يتيح لمحرّك WASM التصريف دون منح 'unsafe-eval' الكامل.
connect-src'none'توجيه مكافحة التسريب. لا تستطيع اللعبة fetch، أو XHR، أو فتح WebSocket، أو الإرسال إلى أي مكان. لا خروج شبكة البتّة.
img-srcdata: (إضافةً إلى أي أصول مظهر، أدناه)صور نقطية مضمَّنة، أو من مضيف أصل مسموح.
media-srcdata: (إضافةً إلى أي أصول مظهر، أدناه)صوت/فيديو مضمَّن، أو من مضيف أصل مسموح.
font-srcdata:خطوط مضمَّنة فقط.
style-src'unsafe-inline'الألعاب تضبط أنماطًا مضمَّنة؛ لا أنساق تنسيق خارجية. (الأنماط لا تستطيع تسريب بيانات كما يفعل السكربت أو الشبكة.)

الأثر الصافي: تعمل اللعبة، وتُعرَض، وتبلّغ نتيجتها عبر جسر الـ SDK، ولا تستطيع بلوغ شيء آخر، خصوصًا لا الشبكة. هذا الـ CSP يضبطه Caputchin وليس شيئًا تعدّه؛ مذكور هنا كي تفهم كم اللعبة محصورة بالضبط.

المكان الوحيد الذي يوسّع فيه إعداد عميل CSP الإطار

تستطيع المظاهر توجيه حقول الصور أو الصوت إلى رابط مطلق على CDN خاصتك (انظر المظاهر). كي تُحمَّل تلك الأصول داخل الإطار المحكَم، يضيف Caputchin أصول تلك الأصول بالضبط فقط إلى img-src / media-src للإطار، ولا شيء سواها. script-src وconnect-src لا يُوسَّعان أبدًا، فحتى أصل أصل مسموح لا يمكن استخدامه لتحميل كود أو فتح قناة شبكة. هذه الطريقة الوحيدة الضيّقة التي تؤثّر بها قيمة مُعَدّة في سياسة الإطار، وهي ما زالت للأصول فقط.

الطبقة 5: قناة نتيجة باتّجاه واحد

ليس للّعبة سطح قابل للنداء إلى صفحتك. المخرج الوحيد جسر الـ SDK: تنادي اللعبة طريقة واحدة تُرسِل بـ postMessage نتيجتها المعتمة (أثرها) إلى الأداة، التي تعيش على أصلك. الأداة هي ما يكلّم API Caputchin؛ واللعبة لا تفعل أبدًا (لا تستطيع، connect-src هو 'none'). فمسار الثقة لعبة ← أداة ← خادمك الخلفي، وكل قفزة تمرّر نتيجة إلى الأمام فقط، لا تمنح اللعبة بلوغًا إلى الوراء أبدًا.

الـ CSP الذي تضبطه على صفحتك

الطبقات أعلاه تحمي أنت وزائرك من اللعبة. Content-Security-Policy على صفحتك أنت ضابط مختلف ومكمّل: يحمي صفحتك من كل شيء، وصُمِّم Caputchin ليعمل تحت واحد صارم. لست مضطرًّا إلى تخفيف CSP لتضمّن Caputchin؛ عليك أن تسمح للأصول القليلة التي تستخدمها الأداة بشكل مشروع.

كحدّ أدنى، تحتاج الأداة إلى:

التوجيهاسمحلماذا
script-srcالأصل الذي تحمّل منه سكربت الأداة، إضافةً إلى 'unsafe-eval'الـ <script> الذي يعرّف <caputchin-widget> / <caputchin-game>، والـ CDN الذي اخترته (jsDelivr، أو مضيفك الخاص، أو caputchin.com). 'unsafe-eval' يتيح تشغيل تحدّي الرصد؛ وهو مطلوب ما دام الرصد مفعّلًا، وتستطيع إسقاطه بإطفاء الرصد على صفحة الأمان للمفتاح.
connect-srchttps://caputchin.comتنادي الأداة API Caputchin لإعداد تحقّق وتأكيده. إن وجّهت الأداة إلى مضيف API مختلف، فاسمح بذلك بدلًا.
frame-srchttps://caputchin.comيحكم إطار اللعبة. ولأن الإطار يستخدم وثيقة srcdoc مضمَّنة، تطبّق المتصفّحات frame-src خاصتك عليه، فاسمح بأصل Caputchin هنا.
worker-srcblob:يعمل حلّال proof-of-work كليًّا في Web Workers منشأة من رابط blob:، بلا ارتداد للخيط الرئيسي، فهذا مطلوب. إن أسقطت worker-src، ترتدّ المتصفّحات إلى child-src ثم default-src، وdefault-src 'self' وحده لا يسمح بـ blob:.

اختياريًّا أضف 'wasm-unsafe-eval' إلى script-src: يتيح لحلّال proof-of-work العمل كـ WebAssembly سريع. ليس مطلوبًا، يرتدّ الحلّال إلى تنفيذ JavaScript خالص أبطأ (ما زال داخل العامل) بدونه.

لا تحتاج إلى السماح بأصل حزمة اللعبة نفسها (jsDelivr، أو CDN لعبة، أو مضيف game-src خاصتك) في CSP صفحتك: تلك الحزمة تُحمَّل داخل الإطار المعزول، تحت CSP الإطار الموصوف أعلاه، لا تحت سياسة صفحتك. صفحتك تؤطّر Caputchin فقط؛ وCaputchin يحصر ما يعمل بالداخل.

إن فشل عنصر Caputchin بصمت في التحميل تحت CSP خاصتك، تسمّي طرفية متصفّحك التوجيه المحجوب؛ أضف الأصل أو الكلمة التي تسمّيها إلى ذلك التوجيه. ابدأ صارمًا وافتح بالضبط ما تطلبه الطرفية. لا تحتاج أبدًا إلى 'unsafe-inline'. تحتاج إلى blob: للعمّال (worker-src)، وما دام الرصد مفعّلًا، إلى 'unsafe-eval' في script-src؛ ويزول متطلّب 'unsafe-eval' إن أطفأت الرصد على صفحة الأمان للمفتاح. 'wasm-unsafe-eval' اختياري (يسرّع حلّال proof-of-work، الذي يعمل بدونه أبطأ بـ JavaScript داخل العامل نفسه).

لماذا كل هذه الطبقات

كل طبقة ستكون حدًّا ذا معنى وحدها؛ ومعًا تعني أن فشل واحدة ليس اختراقًا. الأصل null وحده يعزل اللعبة عن بياناتك أصلًا؛ والـ CSP وحده يقتل خروج الشبكة أصلًا؛ والسلامة وحدها تثبّت البايتات بالضبط أصلًا. يشغّل Caputchin جميعها لأن كود الطرف الثالث غير الموثوق هو بالضبط المكان الذي يستحقّ فيه الدفاع بالعمق أجره.

انظر أيضًا

في هذه الصفحة