سنشرح ما هو cross-site scripting، ونصف الأنواع المختلفة من ثغرات cross-site scripting، ونوضح كيفية العثور على هذه الثغرات ومنعها.
ما هو cross-site scripting (XSS)؟
Cross-site scripting (المعروف أيضًا باسم XSS) هو ثغرة أمنية في الويب تتيح للمهاجم التلاعب بالتفاعلات التي يقوم بها المستخدمون مع تطبيق ضعيف. يسمح XSS للمهاجم بتجاوز سياسة الأصل الواحد (same origin policy)، التي تهدف إلى فصل المواقع المختلفة عن بعضها. عادةً ما تسمح ثغرات cross-site scripting للمهاجم بالتنكر كمستخدم ضحية، للقيام بأي إجراءات يتمكن المستخدم من القيام بها، والوصول إلى أي من بيانات المستخدم. إذا كان لدى المستخدم الضحية وصول مميز داخل التطبيق، فقد يتمكن المهاجم من السيطرة الكاملة على جميع وظائف التطبيق وبياناته.
كيف يعمل XSS؟
يعمل cross-site scripting من خلال التلاعب بموقع ويب ضعيف بحيث يعيد كود JavaScript خبيث إلى المستخدمين. عندما يتم تنفيذ الكود الخبيث داخل متصفح الضحية، يمكن للمهاجم أن يتلاعب تمامًا بتفاعلهم مع التطبيق.
XSS Proof of Concept
يمكنك تأكيد معظم أنواع ثغرات XSS عن طريق حقن حِمل (payload) يتسبب في تنفيذ متصفحك الخاص لبعض أكواد JavaScript العشوائية. لقد كان من الممارسات الشائعة منذ زمن طويل استخدام دالة alert() لهذا الغرض لأنها قصيرة وغير ضارة، ومن الصعب تجاهلها عندما يتم استدعاؤها بنجاح. في الواقع، يمكنك حل غالبية مختبرات XSS لدينا من خلال استدعاء alert() في متصفح الضحية المحاكي.
للأسف، هناك مشكلة صغيرة إذا كنت تستخدم متصفح Chrome. بدءًا من الإصدار 92 (20 يوليو 2021)، يتم منع iframes عبر الأصول من استدعاء alert(). نظرًا لأن هذه تُستخدم لبناء بعض هجمات XSS الأكثر تقدمًا، ستحتاج أحيانًا إلى استخدام حِمل بديل لتأكيد الفكرة (PoC). في هذا السيناريو، نوصي باستخدام دالة print(). إذا كنت مهتمًا بمعرفة المزيد عن هذا التغيير ولماذا نفضل print()، يمكنك الاطلاع على منشور المدونة الخاص بنا حول هذا الموضوع.
نظرًا لأن الضحية المحاكية في مختبراتنا تستخدم Chrome، فقد قمنا بتعديل المختبرات المتأثرة بحيث يمكن أيضًا حلها باستخدام print(). لقد أشرنا إلى ذلك في التعليمات حيثما كان ذلك ذا صلة.
ما هي أنواع هجمات XSS؟
هناك ثلاثة أنواع رئيسية من هجمات XSS. هذه هي:
- Reflected XSS، حيث يأتي النص البرمجي الخبيث من الطلب HTTP الحالي.
- Stored XSS، حيث يأتي النص البرمجي الخبيث من قاعدة بيانات الموقع.
- DOM-based XSS، حيث توجد الثغرة في كود الجهة العميلة بدلاً من كود الجهة الخادمة.
Reflected Cross-site Scripting
تعتبر Reflected XSS أبسط نوع من cross-site scripting. تظهر عندما يستقبل التطبيق بيانات في طلب HTTP ويقوم بتضمين تلك البيانات في الرد الفوري بطريقة غير آمنة.
إليك مثال بسيط على ثغرة Reflected XSS:
https://insecure-website.com/status?message=All+is+well.
<p>Status: All is well.</p>
لا يقوم التطبيق بإجراء أي معالجة أخرى للبيانات، لذا يمكن للمهاجم بسهولة بناء هجوم مثل هذا:
https://insecure-website.com/status?message=<script>/*+Bad+stuff+here...+*/</script>
<p>Status: <script>/* Bad stuff here... */</script></p>
إذا زار المستخدم عنوان URL الذي بناه المهاجم، فإن نص المهاجم يُنفذ في متصفح المستخدم، في سياق جلسة هذا المستخدم مع التطبيق. في تلك اللحظة، يمكن للنص البرمجي تنفيذ أي إجراء، واسترجاع أي بيانات، يمكن للمستخدم الوصول إليها.
Stored Cross-site Scripting
تظهر Stored XSS (المعروفة أيضًا باسم persistent أو second-order XSS) عندما يستقبل التطبيق بيانات من مصدر غير موثوق ويقوم بتضمين تلك البيانات في ردوده اللاحقة على طلبات HTTP بطريقة غير آمنة.
يمكن أن تُرسل البيانات المعنية إلى التطبيق عبر طلبات HTTP؛ على سبيل المثال، التعليقات على منشور مدونة، أو أسماء المستخدمين في غرفة دردشة، أو تفاصيل الاتصال في طلبات العملاء. في حالات أخرى، قد تأتي البيانات من مصادر غير موثوقة أخرى؛ على سبيل المثال، تطبيق بريد ويب يعرض الرسائل المستلمة عبر SMTP، أو تطبيق تسويق يعرض منشورات على وسائل التواصل الاجتماعي، أو تطبيق مراقبة الشبكة الذي يعرض بيانات الحزم من حركة مرور الشبكة.
إليك مثال بسيط على ثغرة Stored XSS. يسمح تطبيق لوحات الرسائل للمستخدمين بإرسال رسائل، والتي تُعرض للمستخدمين الآخرين:
<p>Hello, this is my message!</p>
لا يقوم التطبيق بإجراء أي معالجة أخرى للبيانات، لذا يمكن للمهاجم بسهولة إرسال رسالة تهاجم المستخدمين الآخرين:
<p><script>/* Bad stuff here... */</script></p>
DOM-based Cross-site Scripting
تظهر DOM-based XSS (المعروفة أيضًا باسم DOM XSS) عندما يحتوي التطبيق على بعض أكواد JavaScript من جهة العميل التي تعالج بيانات من مصدر غير موثوق بطريقة غير آمنة، عادةً عن طريق كتابة البيانات مرة أخرى إلى DOM.
في المثال التالي، يستخدم التطبيق بعض أكواد JavaScript لقراءة القيمة من حقل إدخال وكتابة تلك القيمة إلى عنصر داخل HTML:
var search = document.getElementById('search').value;
var results = document.getElementById('results');
results.innerHTML = 'You searched for: ' + search;
إذا كان بإمكان المهاجم التحكم في قيمة حقل الإدخال، فيمكنه بسهولة بناء قيمة خبيثة تتسبب في تنفيذ نصه البرمجي:
You searched for: <img src=1 onerror='/* Bad stuff here... */'>
في حالة نموذجية، سيكون حقل الإدخال مُعبأً من جزء من طلب HTTP، مثل معلمة سلسلة الاستعلام في URL، مما يسمح للمهاجم بتوصيل هجوم باستخدام URL خبيث، بنفس الطريقة كما هو الحال في reflected XSS.
ما الذي يمكن استخدام XSS من أجله؟
عادةً ما يكون المهاجم الذي يستغل ثغرة cross-site scripting قادرًا على:
التنكر كمستخدم ضحية.
تنفيذ أي إجراء يمكن للمستخدم القيام به.
قراءة أي بيانات يمكن للمستخدم الوصول إليها.
التقاط بيانات اعتماد تسجيل الدخول الخاصة بالمستخدم.
إجراء تشويه افتراضي لموقع الويب.
حقن وظائف خبيثة في موقع الويب.
أثر ثغرات XSS
يعتمد الأثر الفعلي لهجوم XSS عمومًا على طبيعة التطبيق، ووظائفه وبياناته، وحالة المستخدم الذي تم اختراقه. على سبيل المثال:
في تطبيق عرض المعلومات، حيث جميع المستخدمين مجهولون وجميع المعلومات عامة، سيكون الأثر غالبًا ضئيلًا.
في تطبيق يحتوي على بيانات حساسة، مثل المعاملات البنكية، أو رسائل البريد الإلكتروني، أو سجلات الرعاية الصحية، سيكون الأثر عادةً خطيرًا.
إذا كان المستخدم المخترق لديه صلاحيات مرتفعة داخل التطبيق، فإن الأثر سيكون عمومًا حرجًا، مما يسمح للمهاجم بالتحكم الكامل في التطبيق الضعيف والتسبب في تعرض جميع المستخدمين وبياناتهم للخطر.
كيفية العثور على ثغرات XSS واختبارها
يمكن العثور على الغالبية العظمى من ثغرات XSS بسرعة وموثوقية باستخدام ماسح ثغرات الويب في Burp Suite.
يتضمن الاختبار اليدوي لثغرات XSS المنعكسة والمخزنة عادةً تقديم بعض المدخلات الفريدة البسيطة (مثل سلسلة أحرف أبجدية رقمية قصيرة) في كل نقطة دخول في التطبيق، وتحديد كل موقع يتم فيه إرجاع المدخلات المقدمة في ردود HTTP، واختبار كل موقع بشكل فردي لتحديد ما إذا كان يمكن استخدام مدخلات مُصممة بشكل مناسب لتنفيذ JavaScript عشوائي. بهذه الطريقة، يمكنك تحديد السياق الذي تحدث فيه XSS واختيار حمولة مناسبة لاستغلالها.
يتضمن الاختبار اليدوي لـ DOM-based XSS الناشئة عن معلمات URL عملية مشابهة: وضع بعض المدخلات الفريدة البسيطة في المعلمة، واستخدام أدوات مطوري المتصفح للبحث في DOM عن هذه المدخلات، واختبار كل موقع لتحديد ما إذا كان قابلاً للاستغلال. ومع ذلك، فإن الأنواع الأخرى من DOM XSS أصعب في الاكتشاف. للعثور على ثغرات DOM في المدخلات غير القائمة على URL (مثل document.cookie) أو sinks غير القائمة على HTML (مثل setTimeout)، لا يوجد بديل عن مراجعة أكواد JavaScript، والتي يمكن أن تكون مستهلكة للوقت بشكل كبير. يجمع ماسح ثغرات الويب في Burp Suite بين التحليل الثابت والديناميكي لـ JavaScript لأتمتة اكتشاف ثغرات DOM بشكل موثوق.
كيفية منع هجمات XSS
يعتبر منع cross-site scripting أمرًا بسيطًا في بعض الحالات، ولكنه يمكن أن يكون أصعب بكثير اعتمادًا على تعقيد التطبيق وطرق التعامل مع البيانات التي يمكن التحكم فيها من قبل المستخدم.
بشكل عام، من المحتمل أن يتطلب منع ثغرات XSS بفعالية مزيجًا من التدابير التالية:
تصفية المدخلات عند الوصول: في النقطة التي يتم فيها استلام مدخلات المستخدم، يجب تصفية المدخلات بشكل صارم بناءً على ما هو متوقع أو المدخلات الصالحة.
ترميز البيانات عند الإخراج: في النقطة التي يتم فيها إخراج البيانات القابلة للتحكم من قبل المستخدم في ردود HTTP، يجب ترميز الإخراج لمنع تفسيره كمحتوى نشط. اعتمادًا على سياق الإخراج، قد يتطلب ذلك تطبيق تركيبات من الترميز HTML، وURL، وJavaScript، وCSS.
استخدام رؤوس الاستجابة المناسبة: لمنع XSS في ردود HTTP التي لا يُقصد بها احتواء أي HTML أو JavaScript، يمكنك استخدام رؤوس Content-Type وX-Content-Type-Options لضمان أن المتصفحات تفسر الردود بالطريقة التي تنويها
سياسة أمان المحتوى (CSP): كخط دفاع أخير، يمكنك استخدام سياسة أمان المحتوى (CSP) لتقليل شدة أي ثغرات XSS لا تزال تحدث.