كل المقالات والفيديوهات

أمان الواجهة الأمامية في تطبيقات المؤسسات: لا تثق بالمتصفح

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

Adil Ben Moussa
08 نوفمبر 2026· 5 دقائق
أمان الواجهة الأمامية في تطبيقات المؤسسات: لا تثق بالمتصفح

زر التحويل معطّل لأن الحد اليومي بلغ أقصاه. لكن أي شخص يفتح يستطيع تفعيله من جديد، أو يتجاهل الزر ويستدعي الـ مباشرة. فإذا كان الحد موجوداً في المكوّن وحده، فالبنك بلا حد.

هذا هو الدرس الأول كله في أمان الواجهة الأمامية لتطبيق مؤسسة: المتصفح هو الجزء الذي لا تتحكم فيه. تستطيع الواجهة الأمامية أن تجعل الهجمات أصعب، لكنها لا يمكن أن تكون المكان الذي تُفرض فيه القاعدة.

المفاهيم القليلة التي تهمّ

التحكم في الوصول يعمل على الخادم. تقولها بوضوح: التحكم في الوصول «لا يكون فعّالاً إلا إذا نُفّذ في كود موثوق على الخادم أو في واجهات برمجية دون خادم». وما زال خلل التحكم في الوصول (broken access control) يتصدّر قائمة OWASP Top 10:2025، ومن نقاط الضعف المذكورة فيها تجاوز عمليات التحقق «بتعديل عنوان URL» والعبث بـ Web Token. التحقق في المكوّن تجربةُ مستخدم. أما التحقق على الخادم فهو القاعدة.

RBAC في الواجهة للوضوح، لا للحماية. أخفِ زر الموافقة عن مستخدم لا يحق له الموافقة، كي تكون الشاشة مفهومة. خذ الأدوار من رد الخادم، وتوقّع أن يرفض الخادم الطلب في كل الأحوال. والواجهة الأمامية التي تقرأ محتوى الرمز () لتقرر ما يحق للمستخدم فعله قد نقلت القرار إلى المكان الوحيد الذي يستطيع المستخدم تعديله.

حرّاس المسارات ( guards) للصلاحيات، على المسار الأب. في ، ضع حارساً واحداً على المسار الأب لقسم كامل، بدل حارس على كل شاشة. فـ canActivateChild «يحدد ما إذا كان المستخدم يستطيع الوصول إلى المسارات الفرعية لمسار أب معيّن»، فتصبح أي شاشة جديدة تحت /admin محمية دون أن يتذكر أحد إضافتها. أما canMatch فيقرر «ما إذا كان يمكن مطابقة المسار أثناء مطابقة المسارات»، وحين يرفض، يجرّب Angular المسارات الأخرى: فالمستخدم الذي لا يملك دور الموافِق قد يصل إلى نسخة للقراءة فقط من المسار نفسه. وكلا الحارسين يقرأ الأدوار من رد الخادم، وتوثيق Angular واضح بشأن الحدود: «لا تعتمد أبداً على حرّاس جانب العميل مصدراً وحيداً للتحكم في الوصول».

XSS: أبقِ أداة التعقيم مفعّلة. يتعامل Angular «مع كل القيم على أنها غير موثوقة افتراضياً»، ويعقّم القيم المربوطة بالـ . توجد دوال bypassSecurityTrust*، لكن التوثيق يقول «انتبه»، لأن الثقة بقيمة خبيثة تفتح ثغرة. ومقابلها في هو dangerouslySetInnerHTML، حيث يعني إدراج غير موثوق أنك «تخاطر بإدخال ثغرة XSS». في المراجعة، اعتبر كليهما ملاحظةً (finding) إلى أن يثبت أحد أن المدخلات موثوقة.

CSP طبقةً ثانية. تصف OWASP سياسة أمان المحتوى (Content Security Policy) القوية بأنها «طبقة حماية ثانية فعّالة»، وتقول إنه «لا ينبغي الاعتماد عليها آليةَ دفاع وحيدة ضد XSS». ويدعم Angular الـ ، وخيار autoCsp للاستضافة الثابتة. ولترى ما يرسله موقعك اليوم، مرّره عبر أداة HTTP Observatory من Mozilla، فهي «تُجري تقييماً معمّقاً لترويسات HTTP في الموقع وغيرها من إعدادات الأمان الأساسية».

الصورة: tt-tech.io، مقتبسة من web.dev، Mitigate cross-site scripting (XSS) with a strict Content Security Policy (CSP)، بترخيص .

الرموز والجلسات. تقول OWASP: «لا تخزّن معرّفات الجلسة في التخزين المحلي، لأن البيانات فيه متاحة دائماً لـ JavaScript»، أما ملفات تعريف الارتباط (cookies) فيمكنها «تخفيف هذا الخطر باستخدام العلامة httpOnly». لكن ملفات تعريف الارتباط تعيد خطر . يقرأ HttpClient في Angular ملف تعريف الارتباط XSRF-TOKEN ويرسله في X-XSRF-TOKEN، والتوثيق واضح في أن هذا الخطر «يجب التصدي له أساساً على جانب الخادم».

لا أسرار في الحزمة، ولا استدعاءات مباشرة لخدمات خارجية. كل ما يُرسل إلى المتصفح علني. ومفتاح API في كود العميل مفتاح منشور. والواجهة الخلفية هي التي تحتفظ بالمفتاح وتستدعي الخدمة الخارجية.

تدقيق دون تسريب. تريد القطاعات الخاضعة للتنظيم أن تعرف من فعل ماذا. وتساعد الواجهة الأمامية في ذلك بمعرّف تفاعل () في كل طلب، وتبقى حذرة فيما تسجّله: تذكر OWASP معرّفات الجلسة، ورموز الوصول، وكلمات المرور، والبيانات الشخصية الحساسة، و«بيانات الحسابات البنكية أو حاملي بطاقات الدفع» بوصفها بيانات لا ينبغي عادةً تسجيلها مباشرة، بل إخفاؤها أو تحويلها إلى بصمة (hash) أو حذفها.

التحقق في المكوّن من أجل المستخدم. والتحقق على الخادم من أجل البنك.

ماذا تختار، ومتى

  • ملف تعريف ارتباط httpOnly أو رمز في الذاكرة: جلسة بملفات تعريف الارتباط عبر واجهة خلفية مخصّصة للواجهة الأمامية () حين تتحكم في الطرفين؛ ورمز قصير العمر في الذاكرة حين تكون الـ API مشتركة مع عملاء آخرين. أما التخزين المحلي فليس مكاناً لمعرّفات الجلسة.
  • CSP بالـ nonces أو بالبصمات (hashes): الـ nonces حين يعرض خادمٌ كل رد؛ وبصمات autoCsp حين يكون التطبيق ملفات ثابتة على .
  • الإخفاء أو التعطيل: أخفِ الإجراءات التي لا يملكها دور معيّن أبداً؛ وعطّل، مع إظهار السبب، الإجراءات التي قد تتاح للمستخدم لاحقاً (حدّ بلغ أقصاه، توقيع ناقص).

في Atlas Bank

يقول ملف القواعد في Atlas Bank: «كل قاعدة عمل تُفرض عند الحدّ.» وتعيش قواعد التحويل في مكان واحد، دالةً نقية في libs/domain/src/lib/transfer-rules.ts. وشاشة التحويل الجديدة في الوحدة 5 (libs/feature/transfers/src/lib/new-transfer.ts على الفرع track1/m5-security-solution) تستدعي canTransfer() داخل computed لتعرض السبب. ثم يستدعيها كود الحدّ مرة أخرى قبل أن يتحرك أي مبلغ، في libs/data-access/banking/src/lib/fake-backend.ts:

// تُفرض القاعدة عند الحدود. يُجري العميل الفحص نفسه من أجل تجربة المستخدم، ويُجريه الخادم فعلياً.
const verdict = canTransfer({ from, toRib, amountMad, transferredTodayMad: this.transferredToday(fromAccountId) });
if (!verdict.ok) throw new Error(blockerMessage[verdict.reason]);

الطبقة الرخيصة آلية. يُفشل eslint.config.mjs أي استدعاء لـ bypassSecurityTrust*، وأي fetch إلى عنوان مطلق. ويُفشل npm run scan:secrets السلاسل النصية التي تطابق أنماط المفاتيح الشائعة في apps/ و libs/. ويعمل كلاهما ضمن npm run lint:arch. وتربط خريطة OWASP للواجهة الأمامية في المستودع كل عائلة مخاطر بما يتحكم فيه فريق الواجهة الأمامية، وهي صريحة بشأن النواقص: CSP، والتعامل مع الرموز، والتسجيل، كلها ليست في العرض التجريبي. ولا يوجد فيه حرّاس مسارات بعد.

ما تركته جانباً، ولماذا

  • اختطاف النقرات ()، و ، وسلامة الموارد الفرعية (). مخاطر حقيقية، ومعظمها ترويسات وإعدادات. سطر واحد لكل منها في قائمة فحص النشر.
  • تدفقات و . يُختار التدفق مع فريق الهوية؛ ودور الواجهة الأمامية هو مكان حفظ الرمز، وقد تناولته أعلاه.
  • التشفير في المتصفح. ليس من مهام الواجهة الأمامية في بنك.

مع بداية الأسبوع

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

لوكيل البرمجة الخاص بك

قواعد هذا المقال، مكتوبة لوكيل. الصقها في ملف AGENTS.md لديك، أو احفظها مهارةً ()، أو وجّه وكيلك إلى الملف.

لوكيل البرمجة الخاص بك تنزيل ملف ‎.md
# Frontend security rules for enterprise apps

Source: https://tt-tech.io/blog/frontend-security-enterprise-untrusted-client
For Angular and React frontends. Add to AGENTS.md or save as a skill. Your project's own rules win where they differ.

## Rules

1. The browser is untrusted. Every access rule and business limit is enforced on the server. A check in a component is only for the user's screen.
2. When you add a client-side check (a limit, a role, a permission), add or find the same check on the server in the same change. If there is none, report it as a finding.
3. Take roles and permissions from the server's answer. Never decide what the user may do by decoding a token in the client.
4. Route guards are for navigation, not protection. Put `canActivateChild` on the parent route of an area, use `canMatch` for role-based variants of a path, and still expect the server to refuse.
5. Hide actions a role never has. Disable, with the reason shown, actions the user could have later (a limit, a missing signature).
6. Keep the sanitizer on. Never call `bypassSecurityTrust*` (Angular) or use `dangerouslySetInnerHTML` (React) on data from a user or an API. If some markup is wanted, map an allowed subset to elements in the template.
7. Never store session ids or tokens in `localStorage` or `sessionStorage`. Use an `httpOnly` cookie session through a backend for frontend, or a short-lived token in memory when the API is shared with other clients.
8. With cookie sessions, keep CSRF protection on: in Angular, `HttpClient` sends the `XSRF-TOKEN` cookie back as an `X-XSRF-TOKEN` header, and the server must check it.
9. No secrets in client code: no API key, token or password in the frontend, not even temporarily. Everything shipped to the browser is public.
10. The browser never calls a third-party service directly. The backend holds the key and makes the call.
11. Treat the Content Security Policy as a second layer: nonces when a server renders each response, `autoCsp` hashes when the app is static files. Do not loosen it to make a script run.
12. Never log tokens, session ids, passwords, personal data or bank and card data from the client. Mask them or leave them out. Send an interaction id with each request instead, so server logs can be matched.

## Before you say done

- Search the diff for `bypassSecurityTrust`, `dangerouslySetInnerHTML`, `localStorage` and strings that look like keys. Remove each hit or explain it in the pull request.
- For every client-side rule in the diff, name the server code that enforces it.
- List what you checked and what you could not check.

المصادر

  1. OWASP, A01 Broken Access Control - OWASP Top 10:2025, 2025
  2. Angular, Control route access with guards
  3. Angular, Security
  4. React, Common components (e.g. <div>)
  5. OWASP, Content Security Policy Cheat Sheet
  6. , HTTP Observatory
  7. OWASP, HTML5 Security Cheat Sheet
  8. OWASP, Logging Cheat Sheet
  9. web.dev, Mitigate cross-site scripting (XSS) with a strict Content Security Policy (CSP)
شارك هذا المقال