Search⌘ K
AI Features

الأمن كحدود للعرض في تطبيقات React

تعلم كيفية التفكير في الأمن كقيد للعرض في React 19، وفهم كيفية دخول البيانات إلى DOM، وكيفية عمل حدود الثقة، وكيف تؤثر بنية جانب العميل على XSS وأمان المصادقة.

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

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

يُؤدي هذا إلى وهمٍ خطير. غالبًا ما يفترض مطورو React أن واجهة المستخدم آمنة بطبيعتها نظرًا لأن JSX تبدو منظمة ومُحكمة. وإلى حدٍ ما، يُساعد React في ذلك، إذ يقوم بتشفير النصوص افتراضيًا. لكن هذا الأمان لا يدوم إلا طالما بقينا ضمن مسار العرض المُحمي لـ React. فبمجرد تجاوزنا لهذا المسار عن طريق حقن HTML خام، أو الاعتماد على عمليات التحقق من المصادقة الخاصة بالعميل فقط، أو تخزين البيانات السرية في مساحة تخزين يُمكن الوصول إليها، فإننا نخرج عن نطاق هذه الحماية.

نادراً ما تبدو الثغرات الأمنية في تطبيقات React خطيرة في البداية، بل تظهر على شكل اختصارات معمارية صغيرة.

  • نقوم بعرض صفحات HTML الخاصة بنظام إدارة المحتوى مباشرةً لأنها مُعقّمة بالفعل.

  • نقوم بتخزين رموز JWT فيlocalStorage لأنه مناسب.

  • نقوم بإخفاء أزرار الإدارة على عميل ونفترض أن ذلك يكفي.

  • نقوم بإدخال معلمات عنوان URL مباشرة في الترميز.

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

يُضفي نموذج العرض في React 19 أهميةً أكبر على هذا الأمر. مع البث المباشر،Suspense عند تحديد الحدود، وعمليات الانتقال بين العميل والخادم، يتم تجميع واجهة المستخدم على مراحل. قد تنشأ البيانات على خادم، وتمر بعملية التسلسل، ثم تُهيأ على عميل، ثم يُعاد عرضها بشكل تفاعلي. إذا لم نحدد بوضوح أين تُبنى الثقة وأين تُفرض، فقد نوسع نطاق الهجمات الإلكترونية عبر هذه المراحل دون قصد.

إذن، المشكلة الحقيقية التي نحاول حلها في هذا الدرس ليست مجرد "كيفية تجنب هجمات XSS". إنها أعمق من ذلك:

  • كيف نصمم تطبيقات React بحيث تبقى البيانات غير الموثوقة بيانات، وليست شفرة قابلة للتنفيذ؟

  • كيف نضمن أنه في حال حدوث خطأ ما أثناء عملية العرض، فلن يتطور الأمر إلى سرقة بيانات الاعتماد؟

  • كيف نمنع عميل من التظاهر بفرض إجراءات أمنية لا يمكن ضمانها حقًا إلا من خادم ؟

لا يُعدّ الأمن في React أمراً ثانوياً، بل هو جزء لا يتجزأ من عملية العرض والتحكم في الحدود. يجب أن نفهم كيف يحمينا React افتراضياً، وأين تنتهي هذه الحماية، وكيف تحافظ قراراتنا المعمارية على هذه الحدود أو تُزيلها.

Security in React is about controlling which paths cross the trust boundary unescaped and where sensitive data can be reached if that boundary fails
Security in React is about controlling which paths cross the trust boundary unescaped and where sensitive data can be reached if that boundary fails

في الرسم التوضيحي أعلاه، تشير الأسهم إلى تدفق البيانات من المدخلات إلى عملية العرض. تمر معظم المسارات عبر آلية الحماية الخاصة بـ React قبل الوصول إلى DOM. أحد المسارات المميزة، عبرdangerouslySetInnerHTML يتجاوز هذا الحاجز ويتدفق مباشرةً إلى منطقة DOM القابلة للتنفيذ. يشير سهم منفصل إلى إمكانية وصول البرامج النصية المُضافة إلى الرموز المخزنة في localStorage.

العرض كحدود أمنية في React

جوهر الأمن في تطبيقات React هو التحكم في كيفية انتقال البيانات عبر حدود الثقة. تنشأ حدود الثقة كلما انتقلت البيانات من مصدر غير موثوق إلى نظام العرض. تشمل الأمثلة إدخال المستخدم، ومعلمات عناوين URL، واستجابات API ، ومحتوى نظام إدارة المحتوى، وعناصر واجهة المستخدم الرسومية الخارجية. بمجرد وصول هذه البيانات إلى نموذج كائن المستند (DOM)، يقرر المتصفح كيفية تفسيرها، وليس React.

يُعدّ سلوك React الافتراضي سلوكًا وقائيًا. فعندما نعرض نصًا مثل{userInput} يقوم React بتهريبها قبل إدراجها في DOM. هذا يعني<script> يصبح نصًا مرئيًا، وليس رمزًا قابلاً للتنفيذ. يشكل هذا الهروب التلقائي حدًا أمنيًا مدمجًا بين البيانات والتنفيذ.

لكن يمكن تجاوز هذا الحد عمدًا. عندما نستخدمdangerouslySetInnerHTML عندئذٍ، نوجه React لإدراج HTML الخام مباشرةً في DOM. في ...