البرمجة العابرة للمواقع، أو XSS، من أكثر الثغرات شيوعًا وأخطرها، وجوهرها بسيط: بيانات غير موثوقة تتسرّب إلى مكان تُنفَّذ فيه كأنها كود. حين يُدرَج مدخل المستخدم في صفحة دون معالجة صحيحة، قد يحتوي على نصّ يُفسَّر كبنية أو كبرنامج، فينفّذه المتصفّح بصلاحيات الصفحة. الدفاع الأساسيّ ليس مرشّحًا سحريًّا، بل مبدأ منضبط: أبقِ البيانات غير الموثوقة خارج السياقات القابلة للتنفيذ، ورمّزها للمكان الدقيق الذي تُدرَج فيه.
جذر المشكلة: خلط البيانات بالكود
تنشأ XSS حين تختلط البيانات بالكود. فالصفحة مزيج من البنية التي يكتبها المطوّر والمحتوى الذي قد يأتي من المستخدم. حين يُدمَج المحتوى في البنية دون حدّ واضح، قد تحتوي البيانات على أحرف تُفسَّر كبنية، فتتجاوز دورها كمحتوى إلى دور تنفيذيّ.
هذا الخلط هو الجذر. فالمتصفّح لا يعرف نيّة المطوّر، بل يفسّر ما يصله وفق قواعد ثابتة. إذا بدا المدخل كوسم أو كبرنامج، عامله كذلك. لذا فإن الدفاع يقوم على الحفاظ على الحدّ بين ما هو بيانات وما هو كود.
الترميز يعتمد على السياق
أهمّ مبدأ في منع XSS أن الترميز الصحيح يعتمد على السياق الذي تُدرَج فيه البيانات. فالبيانات التي تظهر داخل محتوى عنصر تحتاج إلى ترميز مختلف عن تلك داخل قيمة سمة، وكلاهما يختلف عمّا يظهر داخل سياق برمجيّ أو داخل عنوان أو نمط.
هذا يعني أنه لا يوجد ترميز واحد يصلح لكل مكان. الترميز الصحيح لمحتوى عنصر قد يكون عديم الجدوى، بل خطيرًا، في سياق آخر. فهم أن كل سياق له قواعد ترميز خاصة هو حجر الأساس في الدفاع الفعّال.
السياقات الخطرة بوجه خاص
بعض السياقات أخطر من غيرها. فإدراج بيانات غير موثوقة داخل سياق برمجيّ، أو داخل معالج حدث، أو داخل عنوان قد يحمل مخطّطًا تنفيذيًّا، يفتح أبوابًا يصعب إغلاقها بالترميز وحده. هذه السياقات تتطلّب حذرًا مضاعفًا.
القاعدة العملية أن تتجنّب إدراج بيانات غير موثوقة في هذه السياقات الخطرة أصلًا قدر الإمكان. فبعض الأماكن لا يكفي فيها الترميز، ويكون الحلّ الأسلم هو منع البيانات غير الموثوقة من الوصول إليها بدل محاولة تطهيرها. الوقاية هنا أنجع من المعالجة.
الترميز عند المخرج لا عند المدخل
خطأ شائع هو محاولة تطهير البيانات عند استقبالها وتخزينها مطهّرة. لكن هذا هشّ، لأن السياق الذي ستُعرَض فيه البيانات غير معروف وقت الإدخال. البيانات نفسها قد تظهر لاحقًا في سياقات متعدّدة، لكلٍّ منها قواعد ترميز مختلفة.
الأسلم هو الترميز عند المخرج، أي في اللحظة التي تُدرَج فيها البيانات في سياق معيّن. عندئذٍ يكون السياق معروفًا، فيمكن تطبيق الترميز الصحيح له بالضبط. تخزين البيانات خامًا وترميزها عند العرض حسب السياق نهج أكثر متانة ومرونة.
الاعتماد على آليات آمنة افتراضيًّا
محاولة الترميز اليدويّ في كل مكان عرضة للخطأ والنسيان. لذا فإن الاعتماد على آليات تطبّق الترميز الصحيح تلقائيًّا حسب السياق نهج أكثر أمانًا. فالأدوات التي ترمّز المخرجات افتراضيًّا تقلّل احتمال أن ينسى مطوّر ترميز موضع واحد فيفتح ثغرة.
الأمان الافتراضيّ مبدأ مهمّ: اجعل المسار السهل هو المسار الآمن. فحين يكون الترميز الصحيح هو السلوك التلقائيّ، يصبح ترك ثغرة استثناءً يتطلّب جهدًا، لا قاعدة تنشأ من الإهمال. هذا يحوّل الأمان من يقظة دائمة إلى خاصّية مدمجة.
التطهير حين يكون HTML الغنيّ مطلوبًا
الترميز يحلّ الحالة الشائعة حيث نريد عرض مدخل المستخدم كنصّ صرف. لكن تبقى حالة أصعب: حين يُسمَح للمستخدم فعلًا بكتابة محتوى منسّق يحتوي وسومًا، مثل محرّر يتيح الخطّ العريض والروابط والقوائم. هنا لا ينفع الترميز، لأنه سيحوّل الوسوم المقصودة إلى نصّ مرئيّ، فنحتاج بدلًا منه إلى التطهير.
التطهير عملية مختلفة جوهريًّا: فهو يحلّل المحتوى الوارد، ويسمح بقائمة محدّدة من الوسوم والسمات الآمنة، ويحذف كل ما عداها. الفرق الحاسم أن التطهير يعمل بمبدأ القائمة المسموحة لا القائمة الممنوعة؛ فمحاولة حظر كل ما هو خطر محكوم عليها بالفشل، لأن المهاجمين يبتكرون أشكالًا لا تنتهي، بينما السماح بالآمن المعروف فقط يغلق الباب بإحكام.
والقاعدة العملية ألا تكتب مطهّرًا بنفسك، بل تعتمد على مكتبة ناضجة مراجَعة تفهم دقائق تحليل HTML وحالاته الحدّية. فالتحليل اليدويّ بتعبيرات نمطية أو باستبدالات نصية ساذجة يترك ثغرات يصعب حصرها. اختر الترميز حين يكفي، واحجز التطهير للحالات التي يكون فيها المحتوى الغنيّ مطلبًا حقيقيًّا لا رفاهية.
وحتى مع مكتبة جيّدة، يبقى تحديد القائمة المسموحة قرارًا يخصّ تطبيقك أنت. فالسماح بوسوم التنسيق الأساسية شيء، والسماح بالروابط أو الصور أو السمات التي قد تحمل سلوكًا تنفيذيًّا شيء آخر يتطلّب حذرًا أكبر. كلما اتّسعت القائمة المسموحة، اتّسع سطح الهجوم الذي يجب أن تثق بأن المطهّر يغطّيه. لذا ابدأ بأضيق مجموعة تفي بحاجة المستخدم الحقيقية، ووسّعها فقط عند الضرورة المثبتة. هذا التقشّف المتعمّد في ما تسمح به جزء جوهريّ من الدفاع، لأن كل وسم أو سمة تضيفها قرار أمنيّ تتحمّل تبعته. ومن الحكمة أن تراجع هذه القائمة دوريًّا، فما بدا آمنًا في سياق قد يكشف خطرًا حين تتغيّر المتصفّحات أو تظهر أساليب هجوم جديدة، والقائمة الضيّقة المراجَعة أسهل في الحراسة من قائمة واسعة تراكمت عبر الزمن دون تدقيق.
دفاع متعدّد الطبقات
رغم أن الترميز حسب السياق هو الدفاع الأساسيّ، فإنه يقوى بطبقات إضافية. فسياسات تحدّ ممّا يمكن تنفيذه في الصفحة، والتحقّق من المدخلات، والفصل الواضح بين البيانات والكود، كلها تضيف عمقًا للدفاع. لا تعتمد على طبقة واحدة وحدها.
الخلاصة أن منع XSS ليس حيلة واحدة، بل انضباط في التعامل مع الحدّ بين البيانات والكود. حين تبقي البيانات غير الموثوقة خارج السياقات الخطرة، وترمّزها للمكان الدقيق عند المخرج، وتعتمد على آليات آمنة افتراضيًّا، وتضيف طبقات دفاع، تغلق أحد أكثر أبواب الهجوم شيوعًا على الويب.