البرمجة النصية على المواقع الإلكترونية (XSS)، إمكانية إدخال نصوص برمجية ضارة في أحد تطبيقات الويب أكبر ثغرات أمنية على الويب منذ أكثر من عقد.
سياسة أمان المحتوى (CSP)
هي طبقة أمان إضافية تساعد على الحد من تأثير XSS. لإعداد سياسة أمان (CSP)،
إضافة عنوان HTTP يتضمّن العنصر Content-Security-Policy
إلى صفحة ويب وضبط القيم
التحكم في الموارد التي يمكن لوكيل المستخدم تحميلها لتلك الصفحة.
تشرح هذه الصفحة كيفية استخدام سياسة أمان محتوى (CSP) استنادًا إلى nonces أو علامات التجزئة للتخفيف من استخدام XSS، بدلاً من مقدّمي خدمة CSP المستندة إلى القائمة المسموح بها للمضيف والتي غالبًا ما تغادر الصفحة تقنية XSS لأنه يمكن تجاوزها في معظم الإعدادات.
مصطلح رئيسي: رقم غير مباشر هو رقم عشوائي يُستخدم مرة واحدة فقط ويمكنك استخدامه لوضع علامة
العلامة <script>
كموثوق بها
مصطلح رئيسي: دالة التجزئة هي دالة رياضية تحوّل مدخلاً.
إلى قيمة عددية مضغوطة تُسمى تجزئة. يمكنك استخدام التجزئة
(مثل SHA-256) لوضع علامة على مضمّن
العلامة <script>
كموثوق بها
غالبًا ما يُطلق على سياسة أمان المحتوى التي تستند إلى nonces أو التجزئات اسم سياسة CSP صارمة. عندما يستخدم أحد التطبيقات سياسة CSP صارمة، فإنّ المهاجمين الذين يعثرون على رمز HTML فثغرات الحقن لا يمكن أن يستخدمها بشكل عام لإجبار المتصفح على التنفيذ أو النصوص البرمجية الضارة في مستند معرَّض للاختراق. وذلك لأنّ سياسة CSP الصارمة فقط يسمح بالنصوص البرمجية المجزّأة أو النصوص البرمجية ذات القيمة غير الصحيحة التي تم إنشاؤها على الخادم، لذلك لا يمكن للمهاجمين تنفيذ النص البرمجي بدون معرفة الرقم الصحيح لإجابة معينة.
لماذا يجب عليك استخدام سياسة أمان محتوى (CSP) صارمة؟
إذا كان موقعك الإلكتروني يستخدم سياسة أمان محتوى (CSP) تشبه script-src www.googleapis.com
،
فلن يكون فعالاً على مواقع متعددة يسمى هذا النوع من سياسة CSP
القائمة المسموح بها CSP. إنها تتطلب الكثير من التخصيص ويمكن
تجاوزها المهاجمون.
يمكن لـ CSPs الصارم استنادًا إلى أرقام التشفير أو أجزائها تجنُّب هذه المخاطر.
بنية سياسة CSP صارمة
تستخدم نهج أمان المحتوى الأساسي الصارم أحد استجابة HTTP التالية العناوين:
سياسة CSP الصارمة التي لا تستند إلى معايير
Content-Security-Policy:
script-src 'nonce-{RANDOM}' 'strict-dynamic';
object-src 'none';
base-uri 'none';
سياسة CSP الصارمة المستندة إلى التجزئة
Content-Security-Policy:
script-src 'sha256-{HASHED_INLINE_SCRIPT}' 'strict-dynamic';
object-src 'none';
base-uri 'none';
تجعل الخصائص التالية سياسة CSP مثل هذه "صارمة" وبالتالي تكون آمنة:
- تستخدم nonces
'nonce-{RANDOM}'
أو تجزئات'sha256-{HASHED_INLINE_SCRIPT}'
للإشارة إلى علامات<script>
التي يثق مطوِّر الموقع الإلكتروني في تنفيذها متصفح المستخدم. - تضبط
'strict-dynamic'
تقليل الجهد المبذول في نشر سياسة أمان (CSP) لا تعتمد على التجزئة أو علامة تجزئة من خلال تلقائيًا يسمح بتنفيذ النصوص البرمجية التي ينشئها نص برمجي موثوق. هذا أيضًا إزالة حظر استخدام معظم مكتبات وأدوات JavaScript التابعة لجهات خارجية. - لا يستند إلى القوائم المسموح بها لعناوين URL، لذلك لا يتأثر تجاوزات سياسة CSP الشائعة.
- تحظر هذه السياسة النصوص البرمجية المضمّنة غير الموثوق بها، مثل معالِجات الأحداث المضمّنة أو
javascript:
. معرّفات الموارد المنتظمة (URI). - تحظر هذه السياسة
object-src
لإيقاف المكوّنات الإضافية الخطيرة، مثل Flash. - تقيِّد هذه السياسة
base-uri
لحظر إدخال علامات<base>
. وهذا يمنع للمهاجمين من تغيير مواقع النصوص البرمجية التي تم تحميلها من عناوين URL النسبية.
اعتماد سياسة أمان محتوى (CSP) صارمة
لاستخدام سياسة CSP صارمة، يجب:
- حدِّد ما إذا كان يجب أن يضبط تطبيقك سياسة أمان المحتوى (CSP) غير المستندة إلى تجزئة أو مستندة إلى تجزئة.
- انسخ سياسة CSP من قسم بنية سياسة CSP الصارمة واضبطها. كعنوان للاستجابة عبر تطبيقك.
- أعد ضبط نماذج HTML والرمز من جهة العميل لإزالة الأنماط غير متوافق مع سياسة أمان المحتوى (CSP).
- انشر سياسة CSP.
يمكنك استخدام Lighthouse
(الإصدار 7.3.0 والإصدارات الأحدث مع علامة --preset=experimental
) تدقيق أفضل الممارسات
خلال هذه العملية، للتحقّق مما إذا كان موقعك الإلكتروني يتضمّن سياسة CSP، وما إذا كان
صارمة بما يكفي ليكون فعالاً ضد XSS.
الخطوة 1: تحديد ما إذا كنت بحاجة إلى CSP مستند إلى علامة تجزئة أو غير مرتبط به
إليك طريقة عمل نوعَي سياسة CSP الصارمة:
سياسة أمان المحتوى (CSP) المستندة إلى الرقم
باستخدام سياسة أمان محتوى (CSP) لا تستند إلى أي مستخدم، يمكنك إنشاء رقم عشوائي في وقت التشغيل وتضمينه في سياسة CSP وربطها بكل علامة نص برمجي في صفحتك. مهاجم لا يمكن أن تتضمن نصًا ضارًا أو تشغيله في صفحتك، لأنها ستحتاج إلى لتخمين الرقم العشوائي الصحيح لهذا النص. لا يعمل هذا إلا إذا كان الرقم لا يمكن تخمينه، ويتم إنشاؤه حديثًا في وقت التشغيل لكل استجابة.
استخدام سياسة أمان محتوى (CSP) لا تستند إلى الهوية مع صفحات HTML المعروضة على الخادم. بالنسبة لهذه الصفحات، يمكنك إنشاء رقم عشوائي جديد لكل إجابة
سياسة أمان المحتوى (CSP) المستندة إلى التجزئة
بالنسبة إلى سياسة CSP المستندة إلى التجزئة، تتم إضافة تجزئة كل علامة نص برمجي مُضمَّن إلى سياسة CSP. يحتوي كل نص برمجي على تجزئة مختلفة. لا يمكن للمهاجم تضمين برنامج ضار أو تشغيله النصي في صفحتك، لأن تجزئة هذا النص البرمجي ينبغي أن تكون في سياسة CSP لتشغيلها.
استخدام سياسة CSP مستندة إلى علامة التجزئة لصفحات HTML التي يتم عرضها بشكل ثابت أو الصفحات التي يجب مؤقتًا. على سبيل المثال، يمكنك استخدام سياسة CSP مستندة إلى علامة التجزئة لموقع ويب من صفحة واحدة. التطبيقات التي تم إنشاؤها باستخدام أطر عمل مثل Angular أو React أو غيرها، والتي تكون يتم عرضها بشكل ثابت بدون العرض من جهة الخادم.
الخطوة 2: إعداد سياسة CSP صارمة وإعداد نصوصك البرمجية
عند إعداد سياسة أمان (CSP)، يتوفر لك بعض الخيارات:
- وضع إعداد التقارير فقط (
Content-Security-Policy-Report-Only
) أو وضع الفرض (Content-Security-Policy
). وفي وضع إعداد التقارير فقط، لن يحظر سياسة أمان المحتوى (CSP) الموارد حتى الآن، لذلك لا يوجد شيء على موقعك، ولكن يمكنك رؤية الأخطاء للإبلاغ عن أي شيء كان سيتم حظره. محليًا، عندما إعداد سياسة أمان المحتوى (CSP)، فلا يهم حقًا، لأن كلا الوضعين يعرضان لك في وحدة تحكم المتصفح. ويمكن أن يساعدك "وضع التنفيذ"، إن وُجد، في العثور على الموارد التي ستحظرها سياسة CSP، نظرًا لأن حظر أحد الموارد قد يؤدي إلى تبدو الصفحة معطّلة. يصبح وضع "إعداد التقارير فقط" أكثر فائدة لاحقًا في هذه العملية (اطّلِع على الخطوة 5). - العنوان أو علامة HTML
<meta>
بالنسبة إلى التطوير المحلي، يمكن استخدام علامة<meta>
بشكل أكبر طريقة ملائمة لتعديل سياسة CSP ومعرفة مدى تأثيرها على موقعك الإلكتروني بسرعة. في المقابل:- وعند نشر سياسة CSP في مرحلة الإنتاج لاحقًا، ننصحك بضبطها عنوان HTTP.
- إذا كنت ترغب في تعيين سياسة CSP في وضع التقرير فقط، فستحتاج إلى تعيينه باعتباره لأن العلامات الوصفية CSP لا تتيح وضع التقارير فقط.
إعداد استجابة HTTP التالية Content-Security-Policy
في تطبيقك:
Content-Security-Policy: script-src 'nonce-{RANDOM}' 'strict-dynamic'; object-src 'none'; base-uri 'none';
إنشاء رقم nonce مع سياسة أمان المحتوى (CSP)
الرقم الخاص هو رقم عشوائي يتم استخدامه مرة واحدة فقط لكل عملية تحميل للصفحة. غير مستند إلى لا يمكن لـ CSP الحد من تأثير XSS إلا إذا لم يتمكن المهاجمون من تخمين قيمة nonce. حاسمة يجب أن تكون رسالة CSP الخاصة:
- قيمة عشوائية قوية من الناحية المشفرة (يُفضل أن يكون طولها أكثر من 128 بت)
- يتم إنشاؤه حديثًا لكل ردّ
- تم ترميز Base64
في ما يلي بعض الأمثلة حول كيفية إضافة رقم CSP الخاص بأُطر العمل من جهة الخادم:
- Django (لغة بايثون)
- Express (JavaScript):
const app = express(); app.get('/', function(request, response) { // Generate a new random nonce value for every response. const nonce = crypto.randomBytes(16).toString("base64"); // Set the strict nonce-based CSP response header const csp = `script-src 'nonce-${nonce}' 'strict-dynamic'; object-src 'none'; base-uri 'none';`; response.set("Content-Security-Policy", csp); // Every <script> tag in your application should set the `nonce` attribute to this value. response.render(template, { nonce: nonce }); });
إضافة سمة nonce
إلى عناصر <script>
باستخدام سياسة أمان محتوى (CSP) لا تستند إلى أي مستخدم، يجب أن يكون كل عنصر <script>
تحتوي على السمة nonce
التي تطابق القيمة العشوائية الخاصة
المحددة في عنوان CSP. يمكن أن تحتوي جميع النصوص البرمجية على نفس
رقم خاص. الخطوة الأولى هي إضافة هذه السمات إلى جميع النصوص البرمجية حتى
سياسة CSP تسمح لهم.
إعداد استجابة HTTP التالية Content-Security-Policy
في تطبيقك:
Content-Security-Policy: script-src 'sha256-{HASHED_INLINE_SCRIPT}' 'strict-dynamic'; object-src 'none'; base-uri 'none';
بالنسبة إلى النصوص البرمجية المضمّنة المتعددة، تكون البنية كما يلي:
'sha256-{HASHED_INLINE_SCRIPT_1}' 'sha256-{HASHED_INLINE_SCRIPT_2}'
تحميل النصوص البرمجية التي مصدرها ديناميكيًا
بما أنّ تجزئات CSP لا تتوافق إلا مع النصوص البرمجية المضمّنة، يجب تحميل جميع النصوص البرمجية التابعة لجهات خارجية بشكل ديناميكي باستخدام نص برمجي مُضمّن. تكون علامات التجزئة للنصوص البرمجية التي مصدرها غير متوافقة مع جميع المتصفحات.
<script> var scripts = [ 'https://example.org/foo.js', 'https://example.org/bar.js']; scripts.forEach(function(scriptUrl) { var s = document.createElement('script'); s.src = scriptUrl; s.async = false; // to preserve execution order document.head.appendChild(s); }); </script>
<script src="https://example.org/foo.js"></script> <script src="https://example.org/bar.js"></script>
اعتبارات تحميل النص البرمجي
يضيف مثال النص البرمجي المضمّن s.async = false
لضمان
يتم تنفيذ foo
قبل bar
، حتى إذا
يتم تحميل bar
أولاً. في هذا المقتطف: s.async = false
لا يحظر المحلل اللغوي أثناء تحميل النصوص البرمجية، لأن النصوص البرمجية
تتم إضافتها بشكل ديناميكي. يتوقف المحلل اللغوي فقط أثناء تنفيذ البرامج النصية،
بالنسبة إلى نصَّين برمجيَين (async
) ومع ذلك، باستخدام هذا المقتطف،
ضع في اعتبارك ما يلي:
-
قد يتم تنفيذ أحد النصَّين البرمجيَين أو كليهما قبل انتهاء المستند.
التنزيل. إذا كنت تريد أن يكون المستند جاهزًا بحلول الوقت
تنفيذ النصوص البرمجية، يُرجى انتظار الحدث
DOMContentLoaded
قبل تقوم بإلحاق البرامج النصية. إذا تسبب هذا في مشكلة في الأداء لأن لا تبدأ النصوص البرمجية في التنزيل مبكرًا بما فيه الكفاية، استخدِم علامات التحميل المسبق في وقت سابق من الصفحة. -
لا يتخذ "
defer = true
" أي إجراء. إذا كنت بحاجة إلى ذلك تلقائيًا، يمكنك تشغيل النص يدويًا عند الحاجة إليه.
الخطوة 3: إعادة ضبط نماذج HTML والرمز من جهة العميل
معالِجات الأحداث المضمّنة (مثل onclick="…"
وonerror="…"
) ومعرّفات الموارد المنتظمة (URI) بلغة JavaScript
يمكن استخدام (<a href="javascript:…">
) لتشغيل النصوص البرمجية. وهذا يعني أن
عندما يعثر على خطأ XSS، يمكنه إدخال هذا النوع من HTML وتنفيذ النصوص البرمجية الضارة.
JavaScript. يحظر سياسة CSP المستندة إلى سمة لا تعتمد على الهوية أو المستندة إلى التجزئة استخدام هذا النوع من الترميز.
إذا كان موقعك الإلكتروني يستخدم أيًا من هذه الأنماط، عليك إعادة ضبطها لتكون أكثر أمانًا.
والبدائل.
إذا فعّلت سياسة CSP في الخطوة السابقة، ستتمكّن من الاطّلاع على انتهاكات سياسة CSP في وحدة التحكم في كل مرة تحظر فيها سياسة CSP نمطًا غير متوافق.
في معظم الحالات، يكون الحل مباشرًا:
إعادة ضبط معالِجات الأحداث المضمّنة
<span id="things">A thing.</span> <script nonce="${nonce}"> document.getElementById('things').addEventListener('click', doThings); </script>
<span onclick="doThings();">A thing.</span>
إعادة ضبط معرّفات الموارد المنتظمة (URI) لـ javascript:
<a id="foo">foo</a> <script nonce="${nonce}"> document.getElementById('foo').addEventListener('click', linkClicked); </script>
<a href="javascript:linkClicked()">foo</a>
إزالة eval()
من JavaScript
إذا كان تطبيقك يستخدم eval()
لتحويل تسلسلات سلسلة JSON إلى محتوى JavaScript.
فيجب إعادة ضبط هذه الحالات على JSON.parse()
،
أسرع
إذا لم تتمكن من إزالة جميع استخدامات eval()
، لا يزال بإمكانك إعداد إجراء صارم غير يعتمد على
سياسة أمان محتوى (CSP)، ولكن يجب استخدام كلمة CSP الرئيسية 'unsafe-eval'
، مما يجعل
أن تكون السياسة أقل أمانًا بعض الشيء.
يمكنك العثور على هذه الأمثلة والمزيد من الأمثلة لإعادة الهيكلة في سياسة CSP الصارمة هذه. codelab:
الخطوة 4 (اختيارية): إضافة إجراءات احتياطية لإتاحة إصدارات المتصفّح القديمة
إذا كنت بحاجة إلى دعم إصدارات المتصفّح القديمة:
- لاستخدام
strict-dynamic
، يجب إضافةhttps:
كإجراء احتياطي في وقت سابق. من Safari. وعند إجراء ذلك:- تتجاهل جميع المتصفّحات التي تتيح استخدام
strict-dynamic
الإجراء الاحتياطيhttps:
، ولن يؤثّر ذلك في مدى قوة السياسة. - في المتصفحات القديمة، لا يمكن تحميل النصوص البرمجية المصدرة خارجيًا إلا إذا كانت واردة من
مصدر HTTPS. يعد هذا أقل أمانًا من سياسة CSP الصارمة، ولكنه لا يزال
ويمنع بعض أسباب XSS الشائعة، مثل حقن معرّفات الموارد المنتظِمة
javascript:
.
- تتجاهل جميع المتصفّحات التي تتيح استخدام
- لضمان التوافق مع إصدارات المتصفِّح القديمة جدًا (أكثر من 4 سنوات)، يمكنك إضافة
unsafe-inline
كإجراء احتياطي تتجاهل جميع المتصفّحات الحديثةunsafe-inline
. في حال توفّر nonce أو تجزئة سياسة CSP.
Content-Security-Policy:
script-src 'nonce-{random}' 'strict-dynamic' https: 'unsafe-inline';
object-src 'none';
base-uri 'none';
الخطوة 5: نشر سياسة أمان المحتوى (CSP)
بعد التأكّد من أنّ سياسة أمان المحتوى (CSP) لا تحظر أي نصوص برمجية صالحة في تطوير البرامج المحلية، فيمكنك نشر سياسة أمان المحتوى (CSP) على مراحل، ثم إلى بيئة الإنتاج:
- (اختياري) يمكنك نشر سياسة CSP في وضع إعداد التقارير فقط باستخدام
عنوان
Content-Security-Policy-Report-Only
وضع "إعداد التقارير فقط" سهل الاستخدام اختبار تغيير قد يؤدي إلى أعطال في عملية الإنتاج، مثل سياسة أمان محتوى (CSP) جديدة قبل بدء فرض قيود سياسة أمان المحتوى (CSP). في وضع "إعداد التقارير فقط"، لا يتضمن سياسة أمان المحتوى (CSP) تؤثر في سلوك التطبيق، ولكن لا يزال المتصفّح ينشئ أخطاءً في وحدة التحكّم وتقارير المخالفات عند مواجهتها أنماطًا غير متوافقة مع سياسة أمان المحتوى (CSP)، حتى تتمكن من معرفة ما كان يمكن أن يتعطل للمستخدمين النهائيين. لمزيد من المعلومات، معلومات، راجع واجهة برمجة التطبيقات لإعداد التقارير. - إذا كنت واثقًا من أنّ سياسة CSP لن تؤدي إلى إيقاف موقعك الإلكتروني لدى المستخدمين النهائيين،
نشر سياسة CSP باستخدام عنوان الاستجابة
Content-Security-Policy
. أر نقترح إعداد سياسة أمان المحتوى (CSP) باستخدام عنوان HTTP من جهة الخادم لأنها أكثر أكثر أمانًا من علامة<meta>
بعد إكمال هذه الخطوة، يبدأ سياسة أمان المحتوى (CSP) حماية تطبيقك من بروتوكول XSS.
القيود
يوفر سياسة CSP الصارمة عمومًا طبقة أمان إضافية قوية تساعد على
والتخفيف من قيود XSS. وفي معظم الحالات، تقلل سياسة CSP من فرص الهجوم بشكل كبير، وذلك من خلال
رفض الأنماط الخطيرة، مثل معرّفات الموارد المنتظِمة javascript:
ومع ذلك، بناءً على نوع
من سياسة أمان المحتوى (CSP) التي تستخدمها (الرقمية أو التجزئات، مع 'strict-dynamic'
أو بدونها)، هناك
وهي الحالات التي لا يحمي فيها CSP تطبيقك أيضًا:
- إذا لم يتم الرد على أي نص برمجي، ولكن هناك حقن مباشرة في النص أو
مَعلمة
src
للعنصر<script>
هذا. - إذا كان هناك حقن في مواقع النصوص البرمجية التي تم إنشاؤها ديناميكيًا
(
document.createElement('script')
)، بما في ذلك أيّ دوال في المكتبة التي تنشئ عُقدًا DOMscript
استنادًا إلى قيم وسيطاتها. هذا النمط على بعض واجهات برمجة التطبيقات الشائعة مثل.html()
في jQuery، بالإضافة إلى.get()
.post()
في jQuery < الإصدار 3.0 - ما إذا كانت هناك عمليات حقن النماذج في تطبيقات AngularJS القديمة. مهاجم التي يمكنها إدخالها في نموذج AngularJS يمكنها استخدامه تنفيذ محتوى JavaScript عشوائي.
- إذا كانت السياسة تتضمّن
'unsafe-eval'
، الحقن فيeval()
،setTimeout()
، وبعض واجهات برمجة التطبيقات الأخرى التي نادرًا ما يتم استخدامها.
يجب أن يولي المطوّرون ومهندسو الأمان اهتمامًا خاصًا الأنماط أثناء مراجعات الرموز وعمليات تدقيق الأمان. يمكنك العثور على مزيد من التفاصيل على هذه الحالات في سياسة أمان المحتوى: الفوضى الناجحة بين زيادة الحصّة والتخفيف من حدة.