
عزل آمن لأشجار DOM وتغليفها باستخدام ShadowDOM
⚠️ تجريبي [WIP] - الاستخدام على مسؤوليتك الخاصة (اعرف المزيد)
جرّب حظك مع LavaDome - قم بزيارة التطبيق التجريبي، افتح وحدة التحكم، وافعل ما بوسعك لسرقة السر من داخل مثيل LavaDome (أبلغ عن نجاحك)
في ظل معايير الويب الحالية، لا توجد طريقة معتمدة لعزل الأشجار الفرعية من DOM بشكل انتقائي وبطريقة آمنة. بعبارة أخرى، لا يمكننا التحكم في الوصول إلى أقسام من DOM بمنح الوصول لبعض الأطراف ومنعه عن آخرين إذا كانوا يتشاركون بيئة تنفيذ JavaScript نفسها.
نحن نعيش في عالم لم يعد بإمكاننا فيه الثقة بالكود الموجود في تطبيقاتنا الخاصة، وتنفيذ نفس الأصل (same-origin) لا يضمن الأمان. لتأمين الأسرار في الواجهة الأمامية، يجب أن نكون قادرين على عرض المحتوى للمستخدم مع ضمان عدم إمكانية اختراقه بواسطة كود JavaScript يعمل تحت نفس الأصل.

حاليًا، يتم ببساطة إرفاق هذا المحتوى الحساس بـ DOM بمجرد تصديره، مما يجعله متاحًا بالكامل لجميع الكيانات التي تعمل داخل التطبيق نفسه. أي أن أجزاء الكود التي لا ينبغي أن يكون لها حق الوصول إلى المفتاح الخاص يمكنها استخراجه بسهولة كنص صريح، طالما أن الكود الخبيث لديه حق الوصول إلى DOM.
لكن اطمئن. نحن نعتقد أن هذه مشكلة قابلة للحل 👇
LavaDome يدعم حاليًا Vanilla JavaScript و React (مع المزيد قريبًا)
import { LavaDome as LavaDomeJavaScript } from '@lavamoat/lavadome-javascript';
const root = document.getElementById('root'); const lavadome = new LavaDomeJavaScript(root); lavadome.text(secret); lavadome.copy(); // copy to clipboard
### [React](https://github.com/lavamoat/lavadome/blob/main/packages/react)```javascript
import { LavaDome as LavaDomeReact, toLavaDomeToken } from '@lavamoat/lavadome-react';
function Secret({ text }) {
const {token, copy} = toLavaDomeCapabilities(text);
return <>
<a onClick={copy}> copy to clipboard </a>
<LavaDomeReact token={token} />
</>;
}
بالإضافة إلى العقدة الجذرية، تقبل جميع المُنشئات وسيطًا اختياريًا ثانيًا للخيارات:```javascript // javascript new LavaDomeJavaScript(root, { // boolean unsafeOpenModeShadow: false, });
// react function Secret({ text }) { const {token} = toLavaDomeCapabilities(text); return <LavaDomeReact token={token} // boolean unsafeOpenModeShadow={false} /> }
### الاستخدام الآمن
نظرًا لقيود النواة الأساسية للويب، لدمج LavaDome بشكل آمن، هناك عدد من الأمور التي يجب الانتباه إليها وتتطلب جهدًا فعّالًا من المطور الذي يقوم بالدمج:
#### ترتيب التنفيذ
LavaDome، مثل أي برنامج أمان آخر بلغة JavaScript، يكون دائمًا عرضة للكود الذي يعمل قبله.
هذا يعني أنه باستثناء الكود الذي نثق به تمامًا، يجب أن يكون LavaDome أول قطعة كود يتم تحميلها في برنامج تطبيق الويب.
في حين أن هذا لا يعني أن على المطور استخدامه فورًا (بل فقط عند الحاجة إليه)، إلا أنه يجب عليه تضمين البرنامج في أقرب وقت ممكن.
للقيام بذلك بشكل صحيح (آمن)، يجب أن يكون أول تعريف import/require في البرنامج بأكمله:```javascript
import '@lavamoat/lavadome-react';
import 'other-stuff';
console.log('Program starts here');
بهذه الطريقة نضمن أن LavaDome يجهّز نفسه للاستخدام الآمن.
لاحظ أن هذا ينطبق بالمثل على باقي حزم LavaDome وليس فقط @lavamoat/lavadome-react (لذا فإن استيراد أكثر من واحدة منها غير ضروري).
انتقل إلى Security(defensive-coding) لمعرفة المزيد.
بسبب هجمات القنوات الجانبية وقيود الويب، يمكن أن يكون استيراد الخطوط البعيدة تقنية ناجحة ضد LavaDome. وبما أنها مدمجة في مجالات CSS، فإن معالجة هذه المشكلة عبر LavaDome غير ممكنة حاليًا.
لحسن الحظ، يمكن معالجة هذا بشكل فعّال باستخدام توجيه font-src الخاص بـ CSP.
للتخفيف من هذا الشكل من الهجوم، تأكد من أن تطبيق الويب الخاص بك لا يسمح بجلب الخطوط من خوادم غير معروفة.
انتقل إلى Security(side-channeling) لمعرفة المزيد.
يجب أن يكون النص المقدم إلى LavaDome من قبل المطور غير قابل للتنبؤ بنسبة 100%، وإلا فقد يتعرض للهجوم والتسريب.
لذا إذا كان تطبيقك يجب أن يعرض "your key is 234789"، فهذا يعني أن بنية DOM لديك يجب أن تكون:```html
your key is 234789
ويجب ألا يكون:```html
<span> <lavadome>your key is 234789</lavadome> </span>
انتقل إلى الأمان (قابلية الاكتشاف) لمعرفة المزيد.
قد يكون دمج LavaDome أمرًا صعبًا في سياق اختباره، لأن LavaDome بما أنه يقوم بعمل جيد في إخفاء السر، فإنه يخفيه جيدًا أيضًا عن اختباراتك!
لدمج LavaDome بنجاح في بيئة الاختبار الخاصة بك، قد تحتاج إلى بعض المساعدة من LavaDomeDebug الذي يتم تصديره بواسطة @lavamoat/lavadome-core:```javascript
// IMPORT/USE FOR TESTING/DEBUGGING PURPOSES ONLY - NEVER IN PRODUCTION!
import { LavaDomeDebug } from '@lavamoat/lavadome-core';
فيما يلي بعض طرق الأدوات المساعدة للتصحيح التي يصدّرها `LavaDomeDebug` لمساعدتك في اختبار المكونات القائمة على `LavaDome`:
#### `getTextByRoot()`
عند إعطاء جذر مرتبط بـ `LavaDome`، سيقوم `getTextByRoot()` باستخراج السر الداخلي وإعادة بنائه بشكل تكراري. وللسماح بذلك، يجب أن يكون مثيل `LavaDome` قد تم تهيئته في الأصل مع الخيار غير الآمن `@unsafeOpenModeShadow`، مما يجعل الظلال الداخلية لـ `LavaDome` قابلة للوصول من الخارج.
بطبيعة الحال، هذا غير آمن ويجعل `LavaDome` عرضة للخطر تمامًا، لكنه منطقي للاستخدام لأغراض الاختبار/التصحيح فقط - تأكد من عدم تفعيل هذا الخيار أبدًا في الإنتاج!```javascript
new LavaDomeJavaScript(root, {
unsafeOpenModeShadow: isThisTestingEnv, // boolean
}).text('123456');
LavaDomeDebug.getTextByRoot(root) === '123456'; // true
stripDistractionFromText()عند استخدام برامج تشغيل الويب للاختبار وتوجيهها لاستخراج النص الداخلي لجذر مثيل LavaDome، فإنها سترجع سلسلة تحتوي على كلٍّ من السر ونص تشتيت LavaDome.
نص التشتيت مهم للأمان (انظر Security(side-channeling))، لكنه يجعل برنامج تشغيل الويب يستخرج أحرفًا ليست جزءًا من السر فعليًا.
لحل ذلك، وبالنظر إلى النص الذي حصل عليه برنامج تشغيل الويب، سيزيل stripDistractionFromText() نص التشتيت منه، تاركًا فقط السلسلة الدقيقة التي تتوقع اختباراتك العثور عليها.
لا تقلق بشأن نص التشتيت، فلن يكون مرئيًا/قابلاً للتفاعل أبدًا للمستخدم في تطبيقك، لكنه يجب أن يكون موجودًا لأسباب أمنية```javascript new LavaDomeJavaScript(root).text('123456'); const element = await driver.findElement('#ROOT'); // driver const text = await element.getText(); // driver LavaDomeDebug.stripDistractionFromText(text) === '123456'; // true
## التطوير
لإعداد بيئة تطوير محلية لـ **`LavaDome`**، استنسخ هذا المستودع وشغّل أحد الأوامر التالية:```bash
npm install && npm install --global serve
```bash
yarn install && yarn global add serve
## الحل