الفكرة في سطر
Scriptالمهاجم كتبه في كومنت أو URL
Your Pageعرضته كـ HTML
Visitorالمتصفح بتاعه نفّذه
الـ Cross-Site Scripting معناه إن JavaScript مش بتاعك بيشتغل جوه صفحتك، بصلاحيات موقعك: يقرا الصفحة، يبعت requests باسم المستخدم، يسرق tokens متخزنة في localStorage، أو يغيّر الفورم.
التلات أنواع
| النوع | الـ payload بيتخزن فين؟ | مثال |
|---|---|---|
| Stored | في الـ database | كومنت أو bio بيتعرض لكل الزوار |
| Reflected | في الـ request نفسه | بحث بيعرض ?q= في الصفحة من غير encoding |
| DOM-based | في الـ frontend بس | JS بياخد location.hash ويحطه في innerHTML |
React بيحميك… لحد نقطة
React بيعمل escape لأي نص بتحطه بين {}. يعني لو الكومنت فيه tag، هيظهر كنص مش كـ HTML. الثغرات بتيجي من الأبواب الخلفية:
Comment.jsx
// ✅ آمن: React بيعمل escape<p>{comment.body}</p>// ❌ HTML خام من المستخدم<p dangerouslySetInnerHTML={{ __html: comment.body }} />// ❌ لينك المستخدم كتبه: ممكن يبدأ بـ javascript:<a href={user.website}>الموقع</a>SafeHtml.jsx
import DOMPurify from "dompurify";export function SafeHtml({ html }) { const clean = DOMPurify.sanitize(html); return <div dangerouslySetInnerHTML={{ __html: clean }} />;}export function safeUrl(url) { try { const u = new URL(url); return ["https:", "http:"].includes(u.protocol) ? u.href : "#"; } catch { return "#"; }}بره React نفس القاعدة: textContent بدل innerHTML، والـ template engines على السيرفر (EJS و Handlebars) استخدم الصيغة اللي بتعمل escape، مش الـ raw.
الطبقة التانية: Content-Security-Policy
الـ CSP header بيقول للمتصفح: “السكريبتات المسموحة جاية من هنا بس”. لو حد نجح يحقن tag، المتصفح يرفض ينفذه.
server.js
import helmet from "helmet";app.use( helmet.contentSecurityPolicy({ directives: { defaultSrc: ["'self'"], scriptSrc: ["'self'"], // من غير 'unsafe-inline' objectSrc: ["'none'"], baseUri: ["'self'"], frameAncestors: ["'none'"], // هنرجعله في Clickjacking }, }),);خلّصت الفصل لما
🧠 اختبر نفسك
١) بتعرض اسم المستخدم بين أقواس JSX. محتاج sanitize؟
لأ، React بيعمل escape للنص لوحده.
٢) CSP بيغني عن الـ escaping؟
لأ. هو طبقة دفاع تانية لو الأولى فشلت.
٣) ليه لينك المستخدم ممكن يبقى خطر في React؟
لأن href ممكن يبقى
javascript: ويتنفذ لما حد يدوس.