"الأنواع الموثوق بها" هي ميزة أمان تساعد في منع هجمات البرمجة النصية عبر المواقع الإلكترونية المستنِدة إلى نموذج DOM (DOM XSS) من خلال اشتراط تحويل البيانات التي يتم تمريرها إلى واجهات برمجة تطبيقات المتصفّح "الخطيرة" (المعروفة باسم "المصارف") أولاً إلى نوع معيّن، مثل TrustedHTML.
بشكل تلقائي، تقبل العديد من واجهات برمجة تطبيقات DOM (مثل innerHTML أو document.write) السلاسل الأولية. إذا كانت السلسلة تحتوي على نص برمجي ضار من مصدر غير موثوق به، يمكن تنفيذه. تغيّر واجهة برمجة التطبيقات Trusted Types هذا السلوك: بعد تفعيلها من خلال سياسة CSP، لن تقبل هذه المصادر سوى عناصر TrustedHTML التي تم إنشاؤها من خلال سياسات معتمَدة.
تفاصيل التنفيذ الرئيسية
لاستخدام "الأنواع الموثوق بها"، اتّبِع الخطوات الرئيسية الأربع التالية:
- حدِّد سياسة أمان تحدّد كيفية تنظيف السلاسل أو تحويلها.
- استخدِم هذه السياسة لإنشاء عناصر "النوع الموثوق به" من سلاسل أولية.
- استخدِم عناصر Trusted Type عند الكتابة في مخازن DOM.
- فرض استخدام "الأنواع الموثوق بها" من خلال "سياسة أمان المحتوى" (CSP)
1. إنشاء سياسة
السياسة هي مجموعة من القواعد لتنقية المحتوى. يمكنك إنشاؤه باستخدام trustedTypes.createPolicy()، وعادةً ما يتم تفويض ذلك إلى مكتبة تنقية مثل DOMPurify أو قواعد إلغاء HTML في تطبيقك:
import DOMPurify from 'dompurify';
const myPolicy = trustedTypes.createPolicy('sanitize-html', {
createHTML: (input) =>
// Return a sanitized string; createPolicy() wraps it in a TrustedHTML object.
// Example using DOMPurify:
DOMPurify.sanitize(input, { RETURN_TRUSTED_TYPE: false }),
});
// Example using HTML escaping (for environments without third-party sanitizers):
const escapePolicy = trustedTypes.createPolicy('escape-html', {
createHTML: (input) =>
String(input)
.replaceAll('&', '&')
.replaceAll('<', '<')
.replaceAll('>', '>')
.replaceAll('"', '"')
.replaceAll("'", '''),
});
2. استخدام السياسة
بدلاً من تمرير سلسلة مباشرةً إلى مصدر، يمكنك استدعاء طريقة إنشاء السياسة.
const untrustedInput = '<p>Hello, <strong>world</strong>!</p><img src="x" onerror="alert(1)">';
// In an enforced environment, this would throw a TypeError:
// element.innerHTML = untrustedInput;
// This returns a TrustedHTML object with unsafe elements and attributes removed:
const cleanHTML = myPolicy.createHTML(untrustedInput);
// Result: "<p>Hello, <strong>world</strong>!</p><img src=\"x\">"
3- نقل المصادر لاستخدام Trusted Types
عدِّل كل مثيل تكتب فيه إلى مصدر بيانات لتحويله أولاً إلى عنصر من نوع موثوق به. للمساعدة في تحديد مكان تعديل الرمز، يمكنك تحديد سياسة default مؤقتة تسجّل وقت كتابة مخزن باستخدام سلسلة بدلاً من TrustedType.
trustedTypes.createPolicy("default", {
createHTML(value) {
console.warn("String passed instead of Trusted Type.");
return DOMPurify.sanitize(value, { RETURN_TRUSTED_TYPE: false });
},
});
تشمل المصادر الشائعة التي تتوافق مع Trusted Types ما يلي:
- HTML:
element.innerHTMLوelement.outerHTMLوdocument.write()وelement.setHTMLUnsafe()وDocument.parseHTMLUnsafe() - النص: محتوى نصي باللغة
<script>،eval() - ScriptURL:
<script src>,Worker(),SharedWorker()
// Assign the TrustedHTML object.
element.innerHTML = cleanHTML;
يُرجى العِلم أنّ طرق تنقية HTML "الآمنة" (element.setHTML() وDocument.parseHTML()، الموضّحة في مقالة تنقية HTML غير الموثوق بها) لا تتطلّب سياسة "الأنواع الموثوق بها"، لأنّها تنقّي دائمًا هجمات XSS المحتملة بشكلٍ أصلي.
4. فرض استخدام Trusted Types من خلال CSP
يجب طرح Trusted Types بشكل تدريجي لتجنُّب تعطُّل تطبيقك. على الرغم من أنّ إجراء التنفيذ الكامل يوفّر أقوى حماية، إلا أنّه ينطوي على خطر تعطُّل الموقع الإلكتروني إذا لم يتم نقل البيانات كل عمليات الكتابة في المخزن.
المتطلبات الأساسية
- توافق إطار العمل: إذا لم ينتج عن إطار عمل تطبيقك (أو أي مكتبة تابعة لجهة خارجية تكتب في مخازن DOM) قيم
TrustedHTMLأوTrustedScript، لا يمكنك فرض "الأنواع الموثوق بها" بدون إيقاف هذا الرمز. يجب مراجعة مدى توافق إطار العمل قبل بدء عملية الطرح. - إعادة هيكلة المصارف: تأكَّد من تحديد المصارف الخطيرة وإعادة هيكلتها لاستخدام سياسات "الأنواع الموثوق بها".
استراتيجية الطرح
إعداد التقارير فقط: أولاً، يمكنك طرح السياسة باستخدام العنوان
Content-Security-Policy-Report-Only. سيؤدي ذلك إلى تسجيل الانتهاكات في نقطة نهاية إعداد التقارير بدون حظر عمليات الكتابة فعليًا.Content-Security-Policy-Report-Only: require-trusted-types-for 'script';التنفيذ: بعد دمج سياساتك وانخفاض تقارير الانتهاكات إلى الصفر، انتقِل إلى التنفيذ الكامل.
Content-Security-Policy: require-trusted-types-for 'script';
يمكنك أيضًا حصر السياسات المسموح بإنشائها (أدرِج أسماء السياسات، مثل sanitize-html أو escape-html، وأدرِج dompurify إذا كانت سياستك تفوّض DOMPurify.sanitize()، ما يؤدي إلى إنشاء سياسة dompurify داخليًا، وأدرِج default في حال تسجيل سياسة تلقائية أثناء نقل البيانات):
Content-Security-Policy: require-trusted-types-for 'script'; trusted-types sanitize-html escape-html dompurify;
عند تفعيل سياسة CSP هذه، سيؤدي أي إجراء كتابة في مصدر لا يستخدم "الأنواع الموثوق بها" إلى ظهور خطأ. بالإضافة إلى ذلك، ستظهر رسالة خطأ عند محاولة إنشاء سياسة "نوع موثوق به" باسم غير مُدرَج في trusted-types.
يمكنك أيضًا ضبط سياسة أمان المحتوى هذه كعلامة <meta> في <head> المستند، على الرغم من أنّ هذا الإجراء قد يكون أقل أمانًا.
<!-- First child of `<head>`, as earlier tags will not enforce this CSP. -->
<meta
http-equiv="Content-Security-Policy"
content="require-trusted-types-for 'script'; trusted-types sanitize-html escape-html dompurify;"
/>
استراتيجيات احتياطية
بالنسبة إلى المتصفّحات التي لا تتيح استخدام "الأنواع الموثوق بها" بعد، يمكنك استخدام "tinyfill" بسيط لضمان عدم تعطُّل الرمز البرمجي مع الاستمرار في توفير ميزة التعقيم.
if (!window.trustedTypes) {
window.trustedTypes = {
createPolicy: (name, rules) => rules,
};
}
يتيح لك ذلك كتابة الرمز البرمجي باستخدام نمط "الأنواع الموثوق بها" اليوم. ستفرض المتصفحات المتوافقة الأنواع، بينما ستستمر المتصفحات القديمة في تنفيذ منطق التعقيم من خلال السياسة الوهمية.
إذا كان المتصفّح لا يتيح استخدام Trusted Types، سيتعامل مع عناصر TrustedHTML كسلاسل (في حال استخدام tinyfill) أو لن يتم إجراء عملية التحقّق من التنفيذ على مستوى مصدر البيانات.