> ## Content Index
> Fetch the complete content index at: https://arabroot.io/llms.txt
> Use this file to discover other available public pages before exploring further.

# OWASP Top 10 للمبتدئين: أخطر عشر مشكلات في تطبيقات الويب
- URL: https://arabroot.io/articles/owasp-top-10-للمبتدئين/
- Published: 2026-10-06T02:30:00.000Z
- Updated: 2026-10-09T09:43:23.000Z
- Description: أخطر عشر مشكلات أمنية في تطبيقات الويب، كل واحدة بمثال ضعيف ثم مصلح، وكيف تمنعها في الكود وأين تكتشفها.
- Author: فريق عرب رووت
- Tags: الأدلة التقنية, الأمن السيبراني, DevOps وCI/CD, الاستضافة الذاتية

تكتب ميزة جديدة في تطبيقك، صفحة تعرض فاتورة العميل، وتختبرها بحسابك فتعمل، ثم تختبرها بحساب آخر فتعمل أيضاً، فتدمج الكود وتنشره. وبعد شهرين يرسل لك أحد العملاء رسالة يقول فيها إنه غير الرقم في رابط الفاتورة من 1001 إلى 1002 فظهرت له فاتورة شركة أخرى. لم يخترق أحد السيرفر، ولم يكسر أحد التشفير، وإنما سطر واحد في الكود نسي أن يسأل «هل هذه الفاتورة لك؟». وهذا هو حال أغلب الثغرات في تطبيقات الويب، فهي لا تأتي من هجمات معقدة، وإنما من أخطاء متكررة يقع فيها المطورون في كل لغة وفي كل إطار عمل، ولذلك جمعتها مؤسسة OWASP في قائمة واحدة قصيرة يعرفها كل من يعمل في أمن التطبيقات، وهي **OWASP Top 10**.

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

وسوف نناقش في هذا المقال ما يلي:

- ما هي قائمة OWASP Top 10، وكيف تبنى من البيانات Data والاستبيان Survey، وما الذي تغير في نسخة 2025.
- علاقة القائمة بأقاربها: قائمة أمن واجهات API، ومعيار التحقق ASVS، وقاموس نقاط الضعف CWE، وقائمة مخاطر نماذج اللغة LLM Top 10.
- المخاطر العشر واحداً واحداً على تطبيق فواتير صغير، ولكل خطر مثال ضعيف Vulnerable ومثال مصلح Fixed بلغات C# وJava وPython وJavaScript، وطرق المنع Prevention والاكتشاف Detection.
- تجربة عملية Lab صغيرة نرى فيها فحص صلاحيات ناقصاً ثم إصلاحه بأوامر curl ومخرجاتها الحقيقية.
- أين يكتشف كل خطر: في التصميم أم الكود أم البناء أم أثناء التشغيل، ثم مسار القراءة في بقية المرحلة، والأخطاء الشائعة، وقائمة تحقق Checklist.

## ما هي قائمة OWASP Top 10، وما الذي ليست هي؟

مؤسسة **OWASP** (اختصاراً لـ Open Worldwide Application Security Project) مؤسسة غير ربحية تنشر مشاريع مفتوحة في أمن البرمجيات، وأشهر مشاريعها [OWASP Top 10](https://owasp.org/www-project-top-ten/?ref=arabroot.io)، وتصفه صفحة المشروع بأنه «a standard awareness document for developers and web application security»، أي وثيقة توعية Awareness Document للمطورين ولأمن تطبيقات الويب، تمثل اتفاقاً واسعاً على أخطر المخاطر الأمنية في تطبيقات الويب. والنسخة الحالية بحسب صفحة المشروع هي [OWASP Top 10:2025](https://top10.owasp.org/2025/?ref=arabroot.io)، وهي الإصدار الثامن من القائمة كما تقول [مقدمتها](https://top10.owasp.org/2025/0x00%5F2025-Introduction/?ref=arabroot.io)، وقبلها نسختا 2021 و2017.

ولاحظ كلمة «توعية»، فالقائمة تقول عن نفسها في [قسم بناء برنامج أمن التطبيقات](https://top10.owasp.org/2025/0x03%5F2025-Establishing%5Fa%5FModern%5FApplication%5FSecurity%5FProgram/?ref=arabroot.io) إن قوائم Top 10 وثائق توعية، وإنها ليست قائمة كاملة وإنما نقطة بداية. وكل بند فيها ليس ثغرة واحدة، وإنما فئة Category تجمع عدداً من نقاط الضعف المعروفة في قاموس [CWE](https://cwe.mitre.org/?ref=arabroot.io)، ففي نسخة 2025 تحتوي الفئات العشر على 248 نقطة ضعف CWE. وبالتالي فالتطبيق الذي لا يقع في أي من الفئات العشر ليس تطبيقاً آمناً بالضرورة، وإنما تطبيق تجنب أشهر الأخطاء، وهذا في حد ذاته إنجاز جيد لأغلب الفرق.

وقد يتساءل البعض: هل أستطيع أن أقول إن تطبيقي «متوافق مع OWASP Top 10»؟ والإجابة أن القائمة لم تكتب لتكون معياراً للتحقق، فهي تصف المخاطر ولا تعطيك متطلبات قابلة للاختبار، وإذا أردت قائمة متطلبات تتحقق منها في المراجعة أو تطلبها من مورد فالمعيار المناسب هو ASVS، وسوف نرى الفرق بعد قليل.

### كيف تبنى القائمة: البيانات Data والاستبيان Survey

تشرح [مقدمة نسخة 2025](https://top10.owasp.org/2025/0x00%5F2025-Introduction/?ref=arabroot.io) طريقة البناء بالتفصيل، وأهم ما فيها ما يلي:

- **البيانات المساهمة Contributed Data:** جمعت المؤسسة نتائج اختبار لأكثر من 2.8 مليون تطبيق من شركات فحص وأدوات أمنية ومتبرعين لم تذكر أسماؤهم، وحللت 589 نقطة ضعف CWE في هذه البيانات، بعد أن كانت حوالي 30 في نسخة 2017 وقرابة 400 في نسخة 2021.
- **الانتشار Prevalence وليس التكرار Frequency:** السؤال هو كم تطبيقاً فيه نقطة الضعف مرة واحدة على الأقل، وليس كم مرة ظهرت، والسبب أن الأداة الآلية تعد كل تكرار نتيجة مستقلة بينما يكتب الفاحص البشري الثغرة مرة واحدة، فلو حسبنا التكرار لفازت الفئات التي تحبها الأدوات.
- **قابلية الاستغلال Exploitability والأثر Impact:** أخذت المؤسسة درجات CVSS من حوالي 220 ألف ثغرة منشورة CVE مرتبطة بنقاط الضعف، وحسبت لكل CWE متوسط قابلية الاستغلال ومتوسط الأثر.
- **الاستبيان المجتمعي Community Survey:** البيانات تنظر إلى الماضي، لأنها محدودة بما تستطيع الأدوات أن تختبره آلياً، والثغرة الجديدة تحتاج سنوات حتى تدخل في الأدوات، لذلك تختار القائمة ثماني فئات من البيانات، وتترك فئتين يرفعهما المختصون في الاستبيان لأنهم يرونها في عملهم وإن لم تظهر في الأرقام.

وفي نسخة 2025 جاءت فئة سلسلة التوريد A03 وفئة السجلات والتنبيه A09 بأصوات الاستبيان، فالأولى صوت لها نصف المشاركين بالضبط في المرتبة الأولى، والثانية تقول عنها OWASP إنها سوف تبقى دائماً أقل ظهوراً في البيانات مما تستحق، لأن غياب السجل لا تجده أداة فحص.

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

### ما الذي تغير عن نسخة 2021؟

بحسب [المقدمة](https://top10.owasp.org/2025/0x00%5F2025-Introduction/?ref=arabroot.io) هناك فئتان جديدتان ودمج واحد، والتفاصيل كما يلي:

- **التحكم في الوصول المكسور Broken Access Control** بقي في المرتبة الأولى، ودخلت فيه ثغرة طلب السيرفر المزور Server-Side Request Forgery واختصاراً SSRF التي كانت فئة مستقلة في 2021.
- **أخطاء الإعداد الأمني Security Misconfiguration** صعدت من المرتبة الخامسة إلى الثانية، والسبب كما تقول OWASP أن سلوك التطبيقات أصبح يعتمد على الإعدادات أكثر من قبل.
- **أخطاء سلسلة التوريد البرمجية Software Supply Chain Failures** جديدة في المرتبة الثالثة، وهي توسيع لفئة المكونات الضعيفة والقديمة Vulnerable and Outdated Components من 2021 لتشمل خط البناء والتوزيع كله.
- **سوء التعامل مع الحالات الاستثنائية Mishandling of Exceptional Conditions** فئة جديدة في المرتبة العاشرة، تجمع أخطاء التعامل مع الأخطاء والفشل المفتوح Failing Open.
- تغير اسم فئتين قليلاً: «Identification and Authentication Failures» أصبحت **Authentication Failures**، و«Security Logging and Monitoring Failures» أصبحت **Security Logging and Alerting Failures** لأن السجل الذي لا يطلق تنبيهاً قليل الفائدة.

وتذكر OWASP في صفحة [الخطوات التالية](https://top10.owasp.org/2025/X01%5F2025-Next%5FSteps/?ref=arabroot.io) مخاطر كانت قريبة من الدخول ولم تدخل، أولها ضعف قدرة التطبيق على الصمود Lack of Application Resilience، وهي إعادة تسمية لفئة حجب الخدمة Denial of Service، وكانت درجتها قريبة جداً من الفئة العاشرة.

والصورة التالية تبين الفئات العشر مجمعة حسب المكان الذي تبدأ منه في التطبيق، وهذا التجميع من عندنا لتسهيل الفهم:

![خمسة أعمدة، الأول Design وفيه A06 Insecure Design، والثاني Access and identity وفيه A01 Broken Access Control وA07 Authentication Failures، والثالث Your code وفيه A05 Injection وA04 Cryptographic Failures وA10 Mishandling of Exceptional Conditions، والرابع Dependencies and build وفيه A03 Software Supply Chain Failures وA08 Software or Data Integrity Failures، والخامس Config and operations وفيه A02 Security Misconfiguration وA09 Security Logging and Alerting Failures](https://arabroot.io/content/images/2026/10/owasp-top10-01-map.webp)

المخاطر العشر في OWASP Top 10:2025 مجمعة حسب الطبقة التي تبدأ منها: التصميم، والهوية والوصول، والكود، والاعتماديات والبناء، والإعداد والتشغيل

### القائمة وأقاربها: API Security Top 10 وASVS وCWE وLLM Top 10

ستسمع أسماء أخرى قريبة من هذه القائمة، وكل منها له وظيفة مختلفة، والجدول التالي يختصر الفرق:

| الاسم                                                                                                       | ما هو                                                                                                                               | متى تستخدمه                                                              |
| ----------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------ |
| OWASP Top 10:2025                                                                                           | وثيقة توعية بأخطر عشر فئات في تطبيقات الويب                                                                                         | تدريب الفريق، ونقطة بداية لبرنامج أمن التطبيقات                          |
| [OWASP API Security Top 10:2023](https://owasp.org/API-Security/editions/2023/en/0x11-t10/?ref=arabroot.io) | قائمة منفصلة لمخاطر واجهات API، أولها تفويض مستوى الكائن المكسور Broken Object Level Authorization واختصاراً BOLA                   | عندما يكون تطبيقك API يستهلكها تطبيق جوال أو واجهة SPA أو أنظمة أخرى     |
| [OWASP ASVS](https://owasp.org/www-project-application-security-verification-standard/?ref=arabroot.io)     | معيار التحقق من أمن التطبيقات Application Security Verification Standard، وفيه متطلبات مرقمة قابلة للاختبار، وآخر إصدار مستقر 5.0.0 | متطلبات المشروع، ومراجعة الكود، والتعاقد مع مورد أو فاحص                 |
| [CWE](https://cwe.mitre.org/?ref=arabroot.io) من MITRE                                                      | قاموس نقاط الضعف Common Weakness Enumeration، ولكل نقطة رقم مثل CWE-89 لحقن SQL                                                     | لغة مشتركة بين الأدوات والتقارير، فكل أداة SAST تذكر رقم CWE لكل نتيجة   |
| [OWASP Top 10 for LLM Applications](https://genai.owasp.org/llm-top-10/?ref=arabroot.io)                    | قائمة مخاطر التطبيقات المبنية على نماذج اللغة، أولها حقن التعليمات Prompt Injection                                                 | عندما يستقبل تطبيقك نصاً من المستخدم ويمرره إلى نموذج لغة أو أدوات Agent |

وصفحة فئة الحقن A05:2025 نفسها تشير إلى أن نوعاً قريباً من الحقن أصبح شائعاً في نماذج اللغة، وتحيل إلى [LLM01:2025 Prompt Injection](https://genai.owasp.org/llmrisk/llm01-prompt-injection/?ref=arabroot.io)، وقد شرحنا هذا الخطر في قسم [الجودة والأمان في مقال مصطلحات الذكاء الاصطناعي](https://arabroot.io/articles/%D9%85%D8%B5%D8%B7%D9%84%D8%AD%D8%A7%D8%AA-%D8%A7%D9%84%D8%B0%D9%83%D8%A7%D8%A1-%D8%A7%D9%84%D8%A7%D8%B5%D8%B7%D9%86%D8%A7%D8%B9%D9%8A-%D9%88%D9%86%D9%85%D8%A7%D8%B0%D8%AC-%D8%A7%D9%84%D9%84%D8%BA%D8%A9-%D9%84%D9%84%D9%85%D8%A8%D8%AA%D8%AF%D8%A6%D9%8A%D9%86/#safety)، ثم مع الأدوات في قسم [الأمان في مقال بروتوكول MCP](https://arabroot.io/articles/%D8%A8%D8%B1%D9%88%D8%AA%D9%88%D9%83%D9%88%D9%84-mcp-%D9%84%D9%84%D9%85%D8%A8%D8%AA%D8%AF%D8%A6%D9%8A%D9%86/#security). أما قائمة API فلها [مقال مستقل في هذه المرحلة](https://arabroot.io/articles/%D8%A7%D9%85%D9%86-%D9%88%D8%A7%D8%AC%D9%87%D8%A7%D8%AA-api-%D9%85%D8%B9-owasp-api-security-top-10/)، وكذلك [معيار ASVS ومراجعة الكود](https://arabroot.io/articles/%D9%85%D8%AA%D8%B7%D9%84%D8%A8%D8%A7%D8%AA-%D8%A7%D9%84%D8%A7%D9%85%D8%A7%D9%86-%D9%88%D9%85%D8%B1%D8%A7%D8%AC%D8%B9%D8%A9-%D8%A7%D9%84%D9%83%D9%88%D8%AF-%D9%85%D8%B9-owasp-asvs/).

## التطبيق الذي سنمشي عليه في كل خطر

حتى لا تبقى المخاطر أسماء مجردة، سوف نأخذ تطبيقاً واحداً صغيراً ونرى كل خطر فيه، وهو تطبيق فواتير لشركات صغيرة فيه ما يلي:

- تسجيل دخول بالبريد وكلمة المرور، وجلسة Session في Cookie.
- صفحة `/invoices/{id}` تعرض فاتورة، وبحث عن العملاء بالاسم، وتصدير PDF.
- لوحة إدارة Admin Panel لموظفي الشركة، وحجز مقاعد في دورة تدريبية بخصم للمجموعات.
- مكتبات من npm وNuGet وMaven وPyPI، وخط CI يبني Docker Image وينشرها.

ولاحظ أن الأمثلة في كل قسم مختصرة عمداً، فهي تبين الفكرة في سطور قليلة بالشكل الضعيف ثم بالشكل المصلح، أما التطبيق الكامل الذي نكسره ونصلحه خطوة خطوة فهو موضوع مقال [ثغرات الويب بالتجربة](https://arabroot.io/articles/%D8%AB%D8%BA%D8%B1%D8%A7%D8%AA-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D8%A8%D8%A7%D9%84%D8%AA%D8%AC%D8%B1%D8%A8%D8%A9-sql-injection-%D9%88-xss-%D9%88-ssrf/).

## A01:2025 التحكم في الوصول المكسور Broken Access Control

### ما هو بلغة بسيطة؟

التحكم في الوصول Access Control هو القاعدة التي تقول من يحق له أن يفعل ماذا، وتقول [صفحة A01](https://top10.owasp.org/2025/A01%5F2025-Broken%5FAccess%5FControl/?ref=arabroot.io) إنه يفرض سياسة تمنع المستخدم من أن يتصرف خارج صلاحياته، وإن فشله يؤدي إلى كشف بيانات أو تعديلها أو حذفها أو تنفيذ عملية خارج حدود المستخدم. ومن صوره المذكورة في الصفحة: تغيير المعرف في الرابط للوصول إلى سجل غيرك، وهو ما يسمى الإشارة المباشرة غير الآمنة إلى الكائن Insecure Direct Object Reference واختصاراً IDOR، وواجهة API تفحص الصلاحية في GET وتنساها في POST وPUT وDELETE، والعبث بتوكن JWT أو Cookie لرفع الصلاحية، وإعداد CORS خاطئ، والوصول إلى صفحات الإدارة بتخمين الرابط. وفي نسخة 2025 دخلت فيه ثغرة SSRF أيضاً، وهي أن يجعل المستخدم السيرفر يطلب رابطاً داخلياً لم يكن من حقه الوصول إليه.

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

### المثال على تطبيق الفواتير

هذا بالضبط ما رأيناه في بداية المقال، فالمطور تأكد من أن المستخدم سجل دخوله، ثم افترض أن أي مستخدم مسجل يطلب فاتورته هو فقط. والمثال التالي بلغة C# مع ASP.NET Core وEntity Framework Core يبين الشكل الضعيف:

```csharp
// Vulnerable: any logged-in user can read any invoice by changing the id
[Authorize]
[HttpGet("/invoices/{id:int}")]
public async Task<IActionResult> Get(int id)
{
    var invoice = await _db.Invoices.FindAsync(id);
    return invoice is null ? NotFound() : Ok(invoice);
}
```

والشكل المصلح يضع شرط الملكية في الاستعلام نفسه، فلا يمكن أن تخرج فاتورة لا تخص المستخدم الحالي:

```csharp
// Fixed: ownership is part of the query, checked on every request
[Authorize]
[HttpGet("/invoices/{id:int}")]
public async Task<IActionResult> Get(int id)
{
    var userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
    var invoice = await _db.Invoices
        .SingleOrDefaultAsync(i => i.Id == id && i.OwnerId == userId);
    return invoice is null ? NotFound() : Ok(invoice);   // same answer for "not yours" and "not found"
}
```

في الكود أعلاه لاحظ التالي:

- الخاصية `[Authorize]` تجيب عن سؤال المصادقة Authentication، أي «هل أنت مسجل؟»، ولا تجيب عن سؤال التفويض Authorization، أي «هل هذه الفاتورة لك؟»، والخلط بين السؤالين هو أصل هذه الفئة.
- معرف المستخدم يؤخذ من التوكن أو الجلسة التي تحقق منها السيرفر، وليس من حقل في الطلب يستطيع المستخدم أن يغيره.
- الرد واحد في الحالتين، 404 للفاتورة غير الموجودة وللفاتورة التي ليست لك، والسبب أن الرد المختلف يخبر المستخدم أن الرقم 1002 موجود.

والصورة التالية تبين مكان هذا الفحص في مسار الطلب، ولماذا لا يحسب إخفاء الزر في الواجهة فحصاً:

![طلبان من alice، الأول من المتصفح إلى invoices/1001 والثاني بأداة curl إلى invoices/1002 دون المرور بالواجهة، ويدخل الطلبان إلى كود السيرفر حيث يمر كل طلب بثلاث خطوات: authentication ثم authorization يسأل هل الفاتورة 1002 لـ alice ويرفض افتراضياً ثم handler يقرأ الصف من قاعدة البيانات بشرط id وowner أو بسياسة row-level security، ومسار الرفض يرجع 404 مع سطر في السجل، وملاحظة أن إخفاء الزر ليس فحصاً](https://arabroot.io/content/images/2026/10/owasp-top10-02-access-check.webp)

فحص الصلاحية مكانه السيرفر، في كل طلب، بعد معرفة المستخدم وقبل قراءة البيانات، والرفض هو الأصل إذا لم توجد قاعدة تسمح

### تجربة عملية Lab: فحص صلاحيات Authorization Check ناقص ثم إصلاحه

لنرى الفرق بأعيننا، كتبنا خدمة صغيرة جداً بمكتبة Python القياسية وحدها، دون أي مكتبة خارجية، فيها مستخدمان alice وbob ولكل منهما فاتورة، وتعمل بوضعين يحددهما المتغير `MODE`: الوضع الضعيف `vuln` الذي يكتفي بالتأكد من أن المستخدم مسجل، والوضع المصلح `fixed` الذي يفحص الملكية في كل طلب. والملف `app.py` كاملاً كما يلي:

```python
import json, os, re, sys
from http.server import BaseHTTPRequestHandler, HTTPServer

MODE = os.environ.get("MODE", "vuln")          # vuln | fixed

# Two users and their tokens (in a real app: a session or a validated JWT)
TOKENS = {"tok-alice": "alice", "tok-bob": "bob"}

INVOICES = {
    1001: {"id": 1001, "owner": "alice", "amount": 420},
    1002: {"id": 1002, "owner": "bob",   "amount": 9800},
}

class Handler(BaseHTTPRequestHandler):
    def send(self, status, body):
        data = json.dumps(body).encode()
        self.send_response(status)
        self.send_header("Content-Type", "application/json")
        self.send_header("Content-Length", str(len(data)))
        self.end_headers()
        self.wfile.write(data)

    def current_user(self):
        auth = self.headers.get("Authorization", "")
        return TOKENS.get(auth.removeprefix("Bearer "))

    def do_GET(self):
        m = re.fullmatch(r"/invoices/(\d+)", self.path)
        if not m:
            return self.send(404, {"error": "not found"})
        user = self.current_user()
        if user is None:
            return self.send(401, {"error": "login required"})
        invoice = INVOICES.get(int(m.group(1)))

        if MODE == "vuln":
            # Authenticated, so the code trusts the id in the URL
            if invoice is None:
                return self.send(404, {"error": "not found"})
            return self.send(200, invoice)

        # fixed: the server checks ownership on every request, deny by default
        if invoice is None or invoice["owner"] != user:
            print(f"access_denied user={user} invoice={m.group(1)}", file=sys.stderr, flush=True)
            return self.send(404, {"error": "not found"})
        return self.send(200, invoice)

    def log_message(self, fmt, *args):
        pass

HTTPServer(("0.0.0.0", 8000), Handler).serve_forever()
```

ثم شغلنا نسختين من الملف نفسه في Docker Image الرسمية `python:3.12-slim`، الأولى بالوضع الضعيف على المنفذ 20680 والثانية بالوضع المصلح على المنفذ 20681، وكلاهما على `127.0.0.1` فقط، وذلك من المجلد الذي فيه `app.py`:

```bash
docker run -d --name lab-owasp-vuln  -e MODE=vuln  -p 127.0.0.1:20680:8000 \
  -v "$PWD:/app:ro" python:3.12-slim python /app/app.py
docker run -d --name lab-owasp-fixed -e MODE=fixed -p 127.0.0.1:20681:8000 \
  -v "$PWD:/app:ro" python:3.12-slim python /app/app.py
```

الآن نرسل الطلبات نفسها إلى النسخة الضعيفة، فتطلب alice فاتورتها، ثم فاتورة bob، ثم نطلب دون توكن:

```bash
curl -s -w "  HTTP %{http_code}\n" -H "Authorization: Bearer tok-alice" http://127.0.0.1:20680/invoices/1001
curl -s -w "  HTTP %{http_code}\n" -H "Authorization: Bearer tok-alice" http://127.0.0.1:20680/invoices/1002
curl -s -w "  HTTP %{http_code}\n" http://127.0.0.1:20680/invoices/1002
```

والمخرج سوف يكون كما يلي:

```text
{"id": 1001, "owner": "alice", "amount": 420}  HTTP 200
{"id": 1002, "owner": "bob", "amount": 9800}  HTTP 200
{"error": "login required"}  HTTP 401
```

لاحظ أن الطلب الثالث رفض، فالمصادقة تعمل، ومن يختبر التطبيق دون توكن سوف يظن أن كل شيء سليم، ولكن الطلب الثاني أعاد فاتورة bob إلى alice. والآن الطلبات نفسها على النسخة المصلحة، ومعها طلب لفاتورة غير موجودة أصلاً:

```bash
curl -s -w "  HTTP %{http_code}\n" -H "Authorization: Bearer tok-alice" http://127.0.0.1:20681/invoices/1001
curl -s -w "  HTTP %{http_code}\n" -H "Authorization: Bearer tok-alice" http://127.0.0.1:20681/invoices/1002
curl -s -w "  HTTP %{http_code}\n" http://127.0.0.1:20681/invoices/1002
curl -s -w "  HTTP %{http_code}\n" -H "Authorization: Bearer tok-alice" http://127.0.0.1:20681/invoices/1003
docker logs lab-owasp-fixed
```

والمخرج سوف يكون كما يلي:

```text
{"id": 1001, "owner": "alice", "amount": 420}  HTTP 200
{"error": "not found"}  HTTP 404
{"error": "login required"}  HTTP 401
{"error": "not found"}  HTTP 404
access_denied user=alice invoice=1002
access_denied user=alice invoice=1003
```

في المخرج أعلاه لاحظ التالي:

- فاتورة bob وفاتورة 1003 غير الموجودة أعادتا الرد نفسه تماماً، فلا تستطيع alice أن تعرف أي الأرقام موجود.
- كل رفض كتب سطراً في السجل فيه المستخدم والرقم، وهذا ما تطلبه صفحة A01 نفسها، وهو الرابط مع الفئة A09، فمستخدم يجرب عشرين رقماً في دقيقة يجب أن يطلق تنبيهاً.
- الفرق بين النسختين سطر شرط واحد، وهذا هو سبب انتشار هذه الفئة، فلا توجد أداة تعرف أن الفاتورة يجب أن تكون لصاحبها إلا إذا أخبرتها أنت، ولذلك فالحماية الحقيقية اختبار آلي يرسل طلب مستخدم آخر ويتوقع الرفض.

وبعد التجربة حذفنا ال Containers التي أنشأناها بالاسم فقط:

```bash
docker rm -f lab-owasp-vuln lab-owasp-fixed
```

### كيف تمنعه؟

- **الرفض هو الأصل Deny by Default:** كل ما ليس عاماً مرفوض حتى توجد قاعدة تسمح به، والسبب أن نسيان قاعدة يجب أن يغلق الباب لا أن يفتحه.
- **الفحص على السيرفر فقط:** تقول OWASP إن التحكم في الوصول لا يكون فعالاً إلا في كود يثق به السيرفر ولا يستطيع المستخدم تغييره، فإخفاء زر في JavaScript ليس فحصاً، لأن أي مستخدم يستطيع إرسال الطلب بأداة curl.
- **اكتبه مرة واحدة وأعد استخدامه:** مكتبة أو Middleware أو محرك سياسات مركزي، بدل شرط مكتوب يدوياً في كل Endpoint، وقد شرحنا النماذج والمحركات في دليل [الصلاحيات المركزية Authorization مع RBAC وReBAC](https://arabroot.io/articles/%D8%A7%D9%84%D8%B5%D9%84%D8%A7%D8%AD%D9%8A%D8%A7%D8%AA-%D8%A7%D9%84%D9%85%D8%B1%D9%83%D8%B2%D9%8A%D8%A9-authorization-rbac-%D9%88-rebac/).
- **ملكية السجل في الاستعلام:** وإذا كان التطبيق متعدد المستأجرين Multi-Tenant فاجعل قاعدة البيانات نفسها تمنع الخطأ بسياسات الصفوف، كما في قسم [سياسات الصفوف Row-Level Security](https://arabroot.io/articles/%D8%A8%D9%86%D8%A7%D8%A1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-saas-%D9%85%D8%AA%D8%B9%D8%AF%D8%AF-%D8%A7%D9%84%D9%85%D8%B3%D8%AA%D8%A7%D8%AC%D8%B1%D9%8A%D9%86-%D8%B9%D9%85%D9%84%D9%8A%D8%A7/#rls).
- **الجلسات والتوكنات:** ألغ الجلسة على السيرفر عند تسجيل الخروج، واجعل توكن JWT قصير العمر، وقد شرحنا ذلك في دليل [الجلسات وملفات تعريف الارتباط وJWT](https://arabroot.io/articles/%D8%A7%D9%84%D8%AC%D9%84%D8%B3%D8%A7%D8%AA-%D9%88%D9%85%D9%84%D9%81%D8%A7%D8%AA-%D8%AA%D8%B9%D8%B1%D9%8A%D9%81-%D8%A7%D9%84%D8%A7%D8%B1%D8%AA%D8%A8%D8%A7%D8%B7-%D9%88-jwt-%D9%84%D9%84%D9%85%D8%A8%D8%AA%D8%AF%D8%A6%D9%8A%D9%86/).
- **CORS بقائمة محددة:** لا تفتح CORS لكل المصادر لأن الواجهة «لا تعمل»، وقد شرحنا السبب في دليل [CORS وسياسة المصدر الواحد](https://arabroot.io/articles/%D8%B4%D8%B1%D8%AD-cors-%D9%88%D8%B3%D9%8A%D8%A7%D8%B3%D8%A9-%D8%A7%D9%84%D9%85%D8%B5%D8%AF%D8%B1-%D8%A7%D9%84%D9%88%D8%A7%D8%AD%D8%AF/).
- **لا تعتمد على المعرف الصعب التخمين:** المعرف العشوائي مثل UUID يصعب التخمين، لكنه ليس فحص صلاحية، كما ذكرنا في [الملاحظات الأمنية في مقال المعرفات الفريدة](https://arabroot.io/articles/%D8%A7%D9%84%D9%85%D8%B9%D8%B1%D9%81%D8%A7%D8%AA-%D8%A7%D9%84%D9%81%D8%B1%D9%8A%D8%AF%D8%A9-uuid-%D9%88-ulid-%D9%88-snowflake/#security).
- **حدود المعدل Rate Limiting وتسجيل الرفض:** كما في التجربة أعلاه، فكل رفض يسجل، والتكرار يطلق تنبيهاً.

### كيف تكتشفه؟

هذه الفئة من أصعب ما تجده الأدوات، لأن أداة [الفحص الثابت SAST](https://arabroot.io/articles/%D8%AA%D8%AD%D9%84%D9%8A%D9%84-%D8%A7%D9%84%D9%83%D9%88%D8%AF-%D8%A7%D9%84%D8%AB%D8%A7%D8%A8%D8%AA-sast-%D9%85%D8%B9-semgrep-%D9%88-sonarqube/#blind-spots) لا تعرف من يملك ماذا، وأداة [الفحص أثناء التشغيل DAST](https://arabroot.io/articles/%D9%81%D8%AD%D8%B5-%D8%A7%D9%84%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D8%A7%D8%AB%D9%86%D8%A7%D8%A1-%D8%A7%D9%84%D8%AA%D8%B4%D8%BA%D9%8A%D9%84-dast-%D9%85%D8%B9-zap/) تحتاج حسابين مختلفين وسيناريو مكتوباً حتى تلاحظ أن الأول رأى بيانات الثاني. لذلك فأقوى أداة هنا هي اختبارات التكامل Integration Tests التي تكتبها أنت، اختبار لكل Endpoint يرسل طلباً بحساب مستخدم آخر ويتوقع 403 أو 404، ثم مراجعة الكود ونمذجة التهديدات واختبار الاختراق.

## A02:2025 أخطاء الإعداد الأمني Security Misconfiguration

### ما هو بلغة بسيطة؟

تعرف [صفحة A02](https://top10.owasp.org/2025/A02%5F2025-Security%5FMisconfiguration/?ref=arabroot.io) هذه الفئة بأنها نظام أو تطبيق أو خدمة سحابية معدة بشكل خاطئ من الناحية الأمنية، والكود هنا قد يكون سليماً تماماً، ولكن ما حوله مفتوح: حساب افتراضي Default Account بكلمة مرور لم تتغير، ووضع التطوير Debug Mode يعرض تفاصيل الخطأ Stack Trace للزوار، وميزات وخدمات ومنافذ لا يحتاجها أحد، وترويسات الأمان Security Headers غير موجودة، وتخزين سحابي مفتوح للعامة، وعرض محتوى المجلدات Directory Listing. ويدخل فيها أيضاً حقن الكيانات الخارجية في XML واختصاراً XXE، لأن سببه إعداد خاطئ في محلل XML. وقد صعدت هذه الفئة إلى المرتبة الثانية، وتقول OWASP إن ذلك متوقع لأن سلوك البرمجيات أصبح يعتمد على الإعدادات أكثر من أي وقت.

### المثال على تطبيق الفواتير

نسخة الإنتاج Production من التطبيق تعمل بإعداد التطوير، فعندما يحدث خطأ في تصدير PDF يرى العميل صفحة فيها مسارات الملفات على السيرفر وأسماء المكتبات وإصداراتها، وهذه بالضبط المعلومات التي يبحث عنها من يريد أن يعرف أي ثغرة منشورة تناسب تطبيقك. والمثال التالي من ملف `Program.cs` في ASP.NET Core:

```csharp
// Vulnerable: detailed exception pages for everyone, in every environment
var app = builder.Build();
app.UseDeveloperExceptionPage();
```

والشكل المصلح هو ما يولده قالب المشروع نفسه، فصفحة المطور تعمل في بيئة التطوير فقط، وفي غيرها صفحة خطأ عامة والتفاصيل تذهب إلى السجل:

```csharp
// Fixed: generic error page outside Development, details only in the logs
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}
```

ولاحظ أن [توثيق Microsoft](https://learn.microsoft.com/en-us/aspnet/core/fundamentals/error-handling?ref=arabroot.io) يقول إن الوسيط `UseExceptionHandler` يلتقط الاستثناءات التي لم تعالج ويسجلها ثم يعيد تنفيذ الطلب على مسار صفحة الخطأ، ومثله في Spring Boot الخاصية `server.error.include-stacktrace` التي يجب ألا تكون `always` في الإنتاج.

والصورة التالية تبين أن هذه الفئة لا تسكن في ملف واحد، وإنما في كل طبقة حول التطبيق:

![خادم في الوسط مكتوب تحته your web app، وحوله ست بطاقات: cloud storage open to everyone وحلها private by default، وdefault accounts and passwords وحلها no defaults shipped، وdebug mode and stack traces وحلها production profile ومعالج أخطاء مركزي، وmissing security headers وحلها مجموعة ترويسات في ال Reverse Proxy، وports and services nobody needs وحلها الربط على 127.0.0.1 والجدار الناري، وfiles left in the web root مثل directory listing و.git والنسخ الاحتياطية](https://arabroot.io/content/images/2026/10/owasp-top10-05-misconfig.webp)

أسطح أخطاء الإعداد الأمني حول تطبيق واحد، ولكل سطح إصلاحه، والحل المشترك إعداد مكتوب ككود يتكرر في كل بيئة

### كيف تمنعه؟

- **تقوية مكررة Repeatable Hardening:** تطلب OWASP أن تكون بيئات التطوير والاختبار والإنتاج معدة بالطريقة نفسها مع أسرار مختلفة لكل بيئة، وأن تكون العملية آلية، أي إعداد ككود Infrastructure as Code وليس خطوات يدوية يتذكرها شخص واحد.
- **منصة صغيرة Minimal Platform:** احذف ما لا تحتاجه من ميزات وأمثلة وصفحات توثيق وأدوات اختبار، والسبب أن كل ما يعمل ولا تستخدمه سطح لا تراقبه.
- **ترويسات الأمان:** أرسل HSTS وCSP وغيرها من مكان واحد، وقد شرحنا المجموعة الأساسية في دليل [ترويسات الأمان HSTS وCSP](https://arabroot.io/articles/%D8%AA%D8%B1%D9%88%D9%8A%D8%B3%D8%A7%D8%AA-%D8%A7%D9%84%D8%A3%D9%85%D8%A7%D9%86-hsts-%D9%88-csp/)، وإخفاء معلومات الإصدار في قسم [لا تعط المهاجم معلومات مجانية](https://arabroot.io/articles/%D8%AD%D9%85%D8%A7%D9%8A%D8%A9-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D8%B9%D9%84%D9%89-%D9%85%D8%B3%D8%AA%D9%88%D9%89-http/#hide-info).
- **معالج أخطاء مركزي:** صفحة خطأ عامة للمستخدم، والتفاصيل في السجل.
- **لا تضع مفاتيح ثابتة في الإعدادات:** تنصح OWASP باستخدام هوية المنصة وأسرار قصيرة العمر بدل مفاتيح ثابتة في الكود أو ملفات الإعداد أو خط CI.

### كيف تكتشفه؟

هنا تعمل الأدوات جيداً، ففحص ال Images والبنية ككود Infrastructure as Code مع Trivy يقرأ ملفات Dockerfile وKubernetes وTerraform قبل النشر، كما في مقال [فحص ال Images والبنية ككود مع Trivy](https://arabroot.io/articles/%D9%81%D8%AD%D8%B5-%D8%A7%D9%84%D8%AD%D8%A7%D9%88%D9%8A%D8%A7%D8%AA-%D9%88%D8%A7%D9%84%D8%A8%D9%86%D9%8A%D8%A9-%D9%83%D9%83%D9%88%D8%AF-%D9%85%D8%B9-trivy/)، وأداة DAST مثل ZAP تلاحظ الترويسات الناقصة وصفحات الخطأ التفصيلية من الخارج، كما في مقال [الفحص أثناء التشغيل DAST](https://arabroot.io/articles/%D9%81%D8%AD%D8%B5-%D8%A7%D9%84%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D8%A7%D8%AB%D9%86%D8%A7%D8%A1-%D8%A7%D9%84%D8%AA%D8%B4%D8%BA%D9%8A%D9%84-dast-%D9%85%D8%B9-zap/). والقاعدة أن تعيد الفحص بعد كل نشر وليس مرة واحدة، لأن الإعداد يتغير أكثر من الكود.

## A03:2025 أخطاء سلسلة التوريد البرمجية Software Supply Chain Failures

### ما هو بلغة بسيطة؟

تعرف [صفحة A03](https://top10.owasp.org/2025/A03%5F2025-Software%5FSupply%5FChain%5FFailures/?ref=arabroot.io) هذه الفئة بأنها أعطال أو اختراقات في عملية بناء البرمجيات أو توزيعها أو تحديثها، وغالباً سببها ثغرات أو تعديلات خبيثة في كود طرف ثالث أو أدوات أو اعتماديات Dependencies يعتمد عليها نظامك. أي أن السؤال لم يعد فقط «هل في مكتبتي ثغرة معروفة؟»، وهو ما كانت تسأله فئة المكونات القديمة في 2021، وإنما أيضاً «هل المكتبة نفسها من مصدرها الحقيقي؟ وهل خط CI الذي يبني تطبيقي أقل أماناً من التطبيق؟». ومن العلامات التي تذكرها الصفحة: ألا تعرف إصدارات كل مكوناتك بما فيها غير المباشرة Transitive، وأن تؤجل التحديث إلى نافذة شهرية أو ربع سنوية، وأن يستطيع شخص واحد أن يكتب الكود وينشره إلى الإنتاج دون مراجعة من شخص آخر.

وهذه الفئة قليلة الظهور في البيانات، ولكنها بحسب المقدمة صاحبة أعلى متوسط لقابلية الاستغلال والأثر في درجات CVE، وجاءت في المرتبة الأولى في الاستبيان.

### المثال على تطبيق الفواتير

واجهة التطبيق مكتوبة بـ JavaScript، وملف `package.json` يقبل أي إصدار، وخط CI يشغل `npm install` فيأخذ في كل بناء ما هو موجود في المستودع العام ذلك اليوم:

```json
{
  "dependencies": {
    "express": "*"
  }
}
```

والشكل المصلح نطاق إصدار محدد، وملف القفل `package-lock.json` محفوظ في Git، وخط CI يثبت ما في ملف القفل فقط ويفحصه:

```bash
# package.json: "express": "^5.1.0", and package-lock.json is committed
npm ci --ignore-scripts                          # exactly the lock file, fail if it does not match package.json
osv-scanner scan source -L package-lock.json     # known vulnerabilities in direct and transitive packages
```

في الإعداد أعلاه لاحظ التالي:

- بحسب [توثيق npm ci](https://docs.npmjs.com/cli/v11/commands/npm-ci?ref=arabroot.io) فإن الأمر يحتاج ملف قفل موجوداً، ويتوقف بخطأ إذا لم يطابق `package.json` بدل أن يعدله، أي أن ما اختبرته هو ما ينشر.
- الخيار `--ignore-scripts` يمنع تشغيل سكربتات التثبيت في الحزم، وهي الطريقة التي انتشرت بها أكثر من حملة على npm، فإذا احتاجت حزمة معينة سكربتها فاسمح لها وحدها.
- الفحص يقرأ ملف القفل كاملاً، أي المكتبات التي اخترتها والمكتبات التي جاءت معها.

والصورة التالية تبين حلقات السلسلة من جهاز المطور إلى الإنتاج، ومكان A03 وA08 فيها:

![ست حلقات من اليسار: your code و IDE، ثم package registry مثل npm وPyPI وMaven وNuGet، ثم lock file والمكتبات المباشرة وغير المباشرة، ثم CI build، ثم Image registry، ثم production، وتحت كل حلقة خطرها مثل leaked secret وA03 malicious package وA03 vulnerable library وA03 weak pipeline وA08 unsigned artifact وA08 unverified data، وتحتها الفحص المناسب مثل secrets scanning وSCA وSBOM وImage scan وsigning وverify signature وSRI](https://arabroot.io/content/images/2026/10/owasp-top10-04-supply-chain.webp)

أغلب ما يعمل في الإنتاج لم يكتبه فريقك، وA03 يسأل عن سلامة المكون ومصدره، وA08 يسأل هل تحققت من أنه لم يتغير في الطريق

### كيف تمنعه؟

- **قائمة مكونات البرنامج SBOM:** اعرف كل ما في تطبيقك، المباشر وغير المباشر، وراقب قواعد الثغرات مثل CVE وOSV باستمرار، وليس عند البناء فقط.
- **مصادر موثوقة وإصدارات مختارة:** تنصح OWASP بأن تختار الإصدار عمداً ولا تحدث إلا عند الحاجة، وأن تأخذ الحزم من مصادرها الرسمية، وأن تفضل الحزم الموقعة.
- **حماية خط CI والمستودع:** المصادقة متعددة العوامل MFA، وحماية الفروع، وفصل المهام Separation of Duties، وأسرار محصورة في البيئة، وسجلات لا يمكن العبث بها.
- **النشر على مراحل Staged Rollout:** لا تحدث كل الأنظمة في وقت واحد، حتى إذا اخترق مورد موثوق كان الضرر محدوداً.

وقد شرحنا التهديدات والدفاعات على كل حلقة مع حوادثها الموثقة في دليل [أمن سلسلة التوريد البرمجية](https://arabroot.io/articles/%D8%A7%D9%85%D9%86-%D8%B3%D9%84%D8%B3%D9%84%D8%A9-%D8%A7%D9%84%D8%AA%D9%88%D8%B1%D9%8A%D8%AF-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D8%A9-%D9%84%D9%84%D9%85%D8%A8%D8%AA%D8%AF%D8%A6%D9%8A%D9%86/).

### كيف تكتشفه؟

فحص الاعتماديات SCA هو الأداة الرئيسية هنا، وقد شرحناه مع OSV-Scanner وDependency-Track في مقال [فحص الاعتماديات SCA](https://arabroot.io/articles/%D9%81%D8%AD%D8%B5-%D8%A7%D9%84%D8%A7%D8%B9%D8%AA%D9%85%D8%A7%D8%AF%D9%8A%D8%A7%D8%AA-sca-%D9%85%D8%B9-osv-scanner-%D9%88-dependency-track/)، ومعه فحص ال Images في مقال [فحص ال Images والبنية ككود مع Trivy](https://arabroot.io/articles/%D9%81%D8%AD%D8%B5-%D8%A7%D9%84%D8%AD%D8%A7%D9%88%D9%8A%D8%A7%D8%AA-%D9%88%D8%A7%D9%84%D8%A8%D9%86%D9%8A%D8%A9-%D9%83%D9%83%D9%88%D8%AF-%D9%85%D8%B9-trivy/)، وفحص الأسرار المسربة من جهاز المطور وخط CI في مقال [اكتشاف الأسرار المسربة](https://arabroot.io/articles/%D8%A7%D9%83%D8%AA%D8%B4%D8%A7%D9%81-%D8%A7%D9%84%D8%A7%D8%B3%D8%B1%D8%A7%D8%B1-%D8%A7%D9%84%D9%85%D8%B3%D8%B1%D8%A8%D8%A9-%D9%85%D8%B9-gitleaks-%D9%88-trufflehog/).

## A04:2025 أخطاء التشفير Cryptographic Failures

### ما هو بلغة بسيطة؟

تقول [صفحة A04](https://top10.owasp.org/2025/A04%5F2025-Cryptographic%5FFailures/?ref=arabroot.io) إن هذه الفئة تشمل غياب التشفير، أو التشفير الضعيف، أو تسريب المفاتيح، وما يتصل بذلك، وإن ثلاثاً من أكثر نقاط الضعف شيوعاً فيها تتعلق بمولد أرقام عشوائية ضعيف. ومن أسئلتها: هل ترسل بيانات دون TLS؟ هل تستخدم خوارزميات قديمة مثل MD5 وSHA1؟ هل المفاتيح في مستودع الكود؟ هل تستخدم كلمة مرور كمفتاح تشفير دون دالة اشتقاق مفتاح؟ هل العشوائية Randomness التي تستخدمها مصممة للتشفير أصلاً؟

### المثال على تطبيق الفواتير

التطبيق ينشئ رمز إعادة تعيين كلمة المرور Password Reset Token بمولد أرقام عادي، ويحفظ كلمات المرور بهاش MD5، والمثال التالي بلغة Java:

```java
// Vulnerable: predictable token, fast unsalted hash
Random rnd = new Random();
String resetToken = Long.toHexString(rnd.nextLong());

MessageDigest md5 = MessageDigest.getInstance("MD5");
byte[] stored = md5.digest(password.getBytes(StandardCharsets.UTF_8));
```

والشكل المصلح يستخدم مولداً عشوائياً مصمماً للتشفير، ودالة تخزين كلمات مرور بطيئة مع ملح Salt من مكتبة موثوقة، وهنا من Spring Security:

```java
// Fixed: CSPRNG for tokens, a password hashing function with salt and work factor
SecureRandom rnd = new SecureRandom();
byte[] bytes = new byte[32];
rnd.nextBytes(bytes);
String resetToken = Base64.getUrlEncoder().withoutPadding().encodeToString(bytes);

PasswordEncoder encoder = Argon2PasswordEncoder.defaultsForSpringSecurity_v5_8();
String stored = encoder.encode(password);
```

في الكود أعلاه لاحظ التالي:

- الكلاس `java.util.Random` مصمم للمحاكاة والألعاب، وناتجه يمكن توقعه إذا عرفت بعض قيمه، أما `SecureRandom` فمولد مخصص للتشفير، ومثله في Python الوحدة [secrets](https://docs.python.org/3/library/secrets.html?ref=arabroot.io) وفي .NET الكلاس `RandomNumberGenerator`.
- تذكر OWASP في الصفحة نفسها دوال Argon2 وyescrypt وscrypt وPBKDF2-HMAC-SHA-512 لتخزين كلمات المرور، والسبب أنها بطيئة عمداً ومع ملح لكل كلمة، فلا تفيد الجداول المحسوبة مسبقاً، ويصبح التخمين مكلفاً حتى على كروت الشاشة GPU.
- الدالة `Argon2PasswordEncoder.defaultsForSpringSecurity_v5_8()` مذكورة في [توثيق Spring Security لتخزين كلمات المرور](https://docs.spring.io/spring-security/reference/features/authentication/password-storage.html?ref=arabroot.io)، وتحتاج مكتبة Bouncy Castle في المشروع.

### كيف تمنعه؟

- **صنف البيانات Data Classification أولاً:** اعرف أي البيانات حساسة، ولا تخزن ما لا تحتاجه، فالبيانات غير المحفوظة لا يمكن سرقتها كما تقول OWASP.
- **TLS 1.2 فما فوق مع HSTS:** وقد شرحنا الشهادات وسلسلة الثقة في دليل [الشهادات الرقمية TLS وX.509](https://arabroot.io/articles/%D8%A7%D9%84%D8%B4%D9%87%D8%A7%D8%AF%D8%A7%D8%AA-%D8%A7%D9%84%D8%B1%D9%82%D9%85%D9%8A%D8%A9-tls-%D9%88-x509-%D9%88%D8%B5%D9%8A%D8%BA-pem-%D9%88-der/).
- **تشفير موثق Authenticated Encryption:** مثل AES-GCM، بدل التشفير وحده، ولا تكرر ال IV مع المفتاح نفسه أبداً.
- **لا تخترع خوارزميتك:** استخدم مكتبات معروفة، واحفظ المفاتيح في خزنة أسرار Secrets Vault أو وحدة HSM وليس في الكود.
- **استعد للتشفير ما بعد الكم Post-Quantum Cryptography:** تذكر الصفحة أن الأنظمة عالية الخطورة يجب أن تكون آمنة قبل نهاية 2030 بحسب خارطة ENISA.

وتفاصيل الهاش وتخزين كلمات المرور والتشفير المتماثل وغير المتماثل وإدارة المفاتيح هي موضوع مقال [التشفير للمطورين](https://arabroot.io/articles/%D8%A7%D9%84%D8%AA%D8%B4%D9%81%D9%8A%D8%B1-%D9%84%D9%84%D9%85%D8%B7%D9%88%D8%B1%D9%8A%D9%86-%D8%A7%D9%84%D9%87%D8%A7%D8%B4-%D9%88%D9%83%D9%84%D9%85%D8%A7%D8%AA-%D8%A7%D9%84%D9%85%D8%B1%D9%88%D8%B1-%D9%88%D8%A7%D9%84%D9%85%D9%81%D8%A7%D8%AA%D9%8A%D8%AD/) في هذه المرحلة.

### كيف تكتشفه؟

أدوات SAST تجد جيداً استدعاء MD5 وSHA1 و`java.util.Random` في سياق أمني، وفحص الأسرار يجد المفاتيح في المستودع، أما إعداد TLS فيفحص من الخارج بأدوات فحص الشهادات وDAST. والجزء الذي لا تجده الأدوات هو تصنيف البيانات، أي هل كان هذا الحقل يستحق التشفير أصلاً، وهذا مكانه التصميم.

## A05:2025 الحقن Injection

### ما هو بلغة بسيطة؟

تعرف [صفحة A05](https://top10.owasp.org/2025/A05%5F2025-Injection/?ref=arabroot.io) الحقن بأنه خلل يسمح بإرسال مدخلات غير موثوقة من المستخدم إلى مفسر Interpreter مثل المتصفح أو قاعدة البيانات أو سطر الأوامر، فيقوم المفسر بتنفيذ أجزاء من هذه المدخلات كأوامر. والفكرة واحدة في كل أنواعه: حقن SQL، وحقن NoSQL، وحقن أوامر النظام OS Command Injection، وحقن LDAP، وحقن لغات التعبير Expression Language، وكذلك البرمجة عبر المواقع Cross-site Scripting واختصاراً XSS التي تدخل في هذه الفئة، وتقول الصفحة إن XSS كثيرة الحدوث قليلة الأثر بأكثر من 30 ألف CVE، بينما حقن SQL قليل الحدوث كبير الأثر بأكثر من 14 ألف CVE.

والسبب في كل الحالات أن الكود يبني أمراً بدمج نص ثابت مع نص من المستخدم في سلسلة واحدة، فلا يعرف المفسر أين انتهى كودك وأين بدأت البيانات. والصورة التالية تبين ذلك باسم حقيقي فيه علامة اقتباس، وهو كاف ليكسر الاستعلام المبني بالدمج:

![مساران، في الأعلى بالأحمر string concatenation حيث يدخل الاسم O'Brien في نص الاستعلام فتغلق علامة الاقتباس النص مبكراً ويصل إلى محلل SQL نص واحد فيحدث خطأ اليوم أو معنى مختلف غداً، وفي الأسفل بالأخضر parameterised query حيث يرسل الاستعلام الثابت مع علامة الاستفهام في خطوة، والقيمة O'Brien في خطوة منفصلة كبيانات فقط، فيحلل المحلل الاستعلام مرة ثم يربط القيمة](https://arabroot.io/content/images/2026/10/owasp-top10-03-injection.webp)

في الدمج يصل الكود والبيانات في نص واحد، وفي الاستعلام ذي المعاملات Parameterized Query يحلل الاستعلام قبل أن تصل القيمة فلا تستطيع تغيير بنيته

### المثال على تطبيق الفواتير

صفحة البحث عن العملاء بالاسم مكتوبة بلغة Java مع JDBC، والشكل الضعيف يبني الاستعلام بالدمج:

```java
// Vulnerable: user input becomes part of the SQL text
String sql = "SELECT id, name FROM customers WHERE name = '" + name + "'";
ResultSet rs = conn.createStatement().executeQuery(sql);
```

والشكل المصلح استعلام ذو معاملات Parameterized Query، فنص الاستعلام ثابت والقيمة ترسل منفصلة:

```java
// Fixed: the SQL text is fixed, the value is bound as data
PreparedStatement ps = conn.prepareStatement(
        "SELECT id, name FROM customers WHERE name = ?");
ps.setString(1, name);
ResultSet rs = ps.executeQuery();
```

والفكرة نفسها في المتصفح مع XSS، فصفحة نتائج البحث تكتب كلمة البحث في الصفحة، والشكل الضعيف بلغة JavaScript يجعل المتصفح يفسر النص كـ HTML:

```javascript
// Vulnerable: the browser parses the user's text as HTML
results.innerHTML = "<p>Results for " + query + "</p>";
```

```javascript
// Fixed: the text is set as text, never parsed as HTML
const p = document.createElement("p");
p.textContent = "Results for " + query;
results.replaceChildren(p);
```

في الكود أعلاه لاحظ التالي:

- الحل في الحالتين ليس «تنظيف» المدخل، وإنما فصل البيانات عن الأوامر، وهذا ما تقوله OWASP بالنص: أفضل طريقة لمنع الحقن هي إبقاء البيانات منفصلة عن الأوامر والاستعلامات.
- ال ORM يحميك ما دمت تستخدمه بالمعاملات، وتذكر الصفحة مثالاً بلغة HQL في Hibernate يبنى بالدمج فيبقى ضعيفاً، وكذلك الإجراءات المخزنة Stored Procedures إذا دمجت النصوص داخلها.
- أسماء الجداول والأعمدة لا يمكن تمريرها كمعاملات، فإذا كان المستخدم يختار عمود الترتيب مثلاً فاقبل فقط أسماء من قائمة مسموحة Allowlist في الكود.
- في XSS تعتمد أغلب أطر الواجهات مثل React وAngular الترميز التلقائي Output Encoding، والخطر يعود عندما تستخدم الطرق التي تتجاوزه، ومعها سياسة CSP كطبقة ثانية.

📌

في 27 مايو 2023 بدأت مجموعة CL0P باستغلال ثغرة حقن SQL لم تكن معروفة من قبل (CVE-2023-34362) في برنامج نقل الملفات MOVEit Transfer من شركة Progress Software، بحسب [التحذير المشترك AA23-158A من CISA وFBI](https://www.cisa.gov/news-events/cybersecurity-advisories/aa23-158a?ref=arabroot.io)، فزرعت في تطبيقات MOVEit المكشوفة على الإنترنت ملف Web Shell اسمه LEMURLOOT، ثم استخدمته لسرقة البيانات من قواعد بيانات MOVEit نفسها. والدرس أن ثغرة حقن واحدة في تطبيق ويب مكشوف على الإنترنت كانت كافية للوصول إلى قاعدة بياناته، وأن كل منظمة تشغل البرنامج نفسه كانت معرضة للخطأ نفسه حتى تثبت الإصلاح.

### كيف تمنعه؟

- **واجهة آمنة Safe API:** الاستعلامات ذات المعاملات أو ORM، وللأوامر استدعاء البرنامج بقائمة معاملات بدل سطر أوامر يمر عبر ال Shell، والتفاصيل في [OWASP Query Parameterization Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Query%5FParameterization%5FCheat%5FSheet.html?ref=arabroot.io).
- **التحقق من المدخلات Input Validation على السيرفر:** بقائمة مسموحة لما يجب أن يكون عليه المدخل، وتقول OWASP إن هذا ليس دفاعاً كاملاً لأن بعض الحقول تحتاج حروفاً خاصة، فهو طبقة ثانية وليس الحل.
- **ترميز المخرجات Output Encoding حسب السياق:** HTML أو JavaScript أو URL، كما في [OWASP XSS Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Cross%5FSite%5FScripting%5FPrevention%5FCheat%5FSheet.html?ref=arabroot.io).

وكل هذه الأنواع مع تطبيق نكسره ونصلحه في مقال [ثغرات الويب بالتجربة](https://arabroot.io/articles/%D8%AB%D8%BA%D8%B1%D8%A7%D8%AA-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D8%A8%D8%A7%D9%84%D8%AA%D8%AC%D8%B1%D8%A8%D8%A9-sql-injection-%D9%88-xss-%D9%88-ssrf/)، والتحقق من المدخلات وترميز المخرجات بأمثلة في كل لغة في مقال [البرمجة الآمنة Secure Coding](https://arabroot.io/articles/%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%A7%D9%84%D8%A7%D9%85%D9%86%D8%A9-secure-coding-%D9%84%D9%84%D9%85%D8%B7%D9%88%D8%B1%D9%8A%D9%86/).

### كيف تكتشفه؟

هذه أكثر فئة تجيدها الأدوات، فأداة SAST تتبع المدخل من مصدره Source إلى الدالة الخطرة Sink، كما رأينا في مقال [الفحص الثابت SAST](https://arabroot.io/articles/%D8%AA%D8%AD%D9%84%D9%8A%D9%84-%D8%A7%D9%84%D9%83%D9%88%D8%AF-%D8%A7%D9%84%D8%AB%D8%A7%D8%A8%D8%AA-sast-%D9%85%D8%B9-semgrep-%D9%88-sonarqube/)، وأداة DAST ترسل مدخلات إلى كل حقل وتراقب الرد. وتقول صفحة A05 إن الاكتشاف الأفضل هو الجمع بين مراجعة الكود والاختبار الآلي لكل المعاملات والترويسات والروابط وملفات تعريف الارتباط وبيانات JSON وXML.

## A06:2025 التصميم غير الآمن Insecure Design

### ما هو بلغة بسيطة؟

هذه الفئة مختلفة عن غيرها، فهي لا تتكلم عن خطأ في سطر، وإنما عن ضابط أمني Security Control لم يصمم أصلاً، وتقول [صفحة A06](https://top10.owasp.org/2025/A06%5F2025-Insecure%5FDesign/?ref=arabroot.io) إن التصميم الآمن قد يحتوي على أخطاء في التنفيذ، أما التصميم غير الآمن فلا يصلحه تنفيذ مثالي، لأن الضوابط المطلوبة لم تصنع للدفاع ضد هجمات محددة. ويدخل فيها منطق العمل Business Logic، مثل أن تسمح المنظومة بحالة لم يفكر فيها أحد، وأسئلة استعادة الحساب السرية Security Questions التي تقول الصفحة إن NIST 800-63b وASVS وOWASP Top 10 تمنعها، لأن أكثر من شخص قد يعرف إجاباتها.

### المثال على تطبيق الفواتير

تذكر الصفحة مثال سلسلة سينما تسمح بخصم الحجز الجماعي حتى خمسة عشر شخصاً قبل أن تطلب عربوناً، ثم يحجز أحدهم ستمئة مقعد في كل الصالات بطلبات قليلة. وفي تطبيقنا حجز مقاعد الدورة التدريبية بالخصم الجماعي، والحد مكتوب فقط في نموذج الصفحة `max="15"`، والسعر يحسب كما يرسله الطلب، والمثال التالي بلغة Python مع Flask:

```python
# Vulnerable: the limit exists only in the HTML form, nothing on the server
@app.post("/bookings")
def book():
    seats = int(request.json["seats"])
    price = seats * SEAT_PRICE * (0.8 if seats >= 5 else 1)
    return create_booking(current_user(), seats, price)
```

```python
# Fixed: the business rules from the design are enforced on the server
MAX_SEATS_WITHOUT_DEPOSIT = 15
MAX_BOOKINGS_PER_DAY = 3

@app.post("/bookings")
def book():
    seats = int(request.json["seats"])
    if not 1 <= seats <= MAX_SEATS_WITHOUT_DEPOSIT:
        abort(422, "group bookings above 15 seats need a deposit")
    if bookings_today(current_user()) >= MAX_BOOKINGS_PER_DAY:
        abort(429, "too many bookings today")
    price = seats * SEAT_PRICE * (0.8 if seats >= 5 else 1)   # computed on the server only
    return create_booking(current_user(), seats, price)
```

ولاحظ أن الإصلاح هنا ليس سطراً تقنياً ذكياً، وإنما قاعدتان من قواعد العمل كتبهما أحد في المتطلبات، أي أن أحداً سأل في مرحلة التصميم «ماذا لو حجز أحدهم ستمئة مقعد؟»، ولو لم يسأل هذا السؤال لما وجدته أي أداة، لأن الكود الأول لا يحتوي على أي دالة خطرة.

### كيف تمنعه؟

- **نمذجة التهديدات Threat Modeling:** تطلبها OWASP للأجزاء الحرجة مثل المصادقة والتحكم في الوصول ومنطق العمل والمسارات الأساسية، وقد شرحناها مع STRIDE في دليل [نمذجة التهديدات Threat Modeling](https://arabroot.io/articles/%D9%86%D9%85%D8%B0%D8%AC%D8%A9-%D8%A7%D9%84%D8%AA%D9%87%D8%AF%D9%8A%D8%AF%D8%A7%D8%AA-threat-modeling-%D9%84%D9%84%D9%85%D8%A8%D8%AA%D8%AF%D8%A6%D9%8A%D9%86/).
- **حالات سوء الاستخدام Misuse Cases:** بجانب كل قصة مستخدم User Story، اكتب ما يجب ألا يحدث، ثم اختباراً يتأكد من ذلك.
- **مكتبة أنماط آمنة Secure Design Patterns:** مكونات جاهزة مجربة للمصادقة والصلاحيات والملفات، بدل أن يخترع كل فريق طريقته.
- **فصل المستأجرين Tenants بالتصميم:** في كل الطبقات، وليس بشرط في الاستعلام فقط.

### كيف تكتشفه؟

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

## A07:2025 أخطاء المصادقة Authentication Failures

### ما هو بلغة بسيطة؟

تقول [صفحة A07](https://top10.owasp.org/2025/A07%5F2025-Authentication%5FFailures/?ref=arabroot.io) إن هذه الثغرة موجودة عندما يستطيع المهاجم أن يجعل النظام يقبل مستخدماً غير صحيح على أنه صحيح. ومن صورها: السماح بهجمات حشو بيانات الدخول Credential Stuffing التي تجرب قوائم أسماء وكلمات مرور مسربة من مواقع أخرى، وعدم إيقاف التخمين الآلي Brute Force، وقبول كلمات مرور ضعيفة أو مسربة، واستعادة الحساب بأسئلة سرية، وغياب المصادقة متعددة العوامل MFA، ووضع معرف الجلسة Session ID في الرابط، وعدم تغييره بعد الدخول، وعدم إلغائه عند الخروج.

### المثال على تطبيق الفواتير

صفحة الدخول تخبر الزائر أي الحقلين خطأ، فتقول له «لا يوجد حساب بهذا البريد» أو «كلمة المرور خاطئة»، ولا تقفل الحساب بعد المحاولات الفاشلة، والمثال التالي بلغة C# مع ASP.NET Core Identity:

```csharp
// Vulnerable: tells which emails exist, never slows down guessing
var user = await _users.FindByEmailAsync(model.Email);
if (user is null) return BadRequest("No account with this email");
var result = await _signIn.PasswordSignInAsync(user, model.Password,
                                               isPersistent: false, lockoutOnFailure: false);
if (!result.Succeeded) return BadRequest("Wrong password");
```

```csharp
// Fixed: one message for every failure, lockout after repeated failures
var result = await _signIn.PasswordSignInAsync(model.Email, model.Password,
                                               isPersistent: false, lockoutOnFailure: true);
if (!result.Succeeded) return BadRequest("Invalid email or password.");
```

في الكود أعلاه لاحظ التالي:

- الرسالة الواحدة لكل الحالات هي ما تطلبه OWASP نصاً، لأن الرسالتين المختلفتين تعطيان المهاجم قائمة البريد المسجل في تطبيقك، وهذا يشمل صفحة التسجيل واستعادة كلمة المرور أيضاً.
- المعامل `lockoutOnFailure` في [الدالة PasswordSignInAsync](https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.identity.signinmanager-1.passwordsigninasync?ref=arabroot.io) يفعل القفل المؤقت بعد عدد من المحاولات الفاشلة حسب إعدادات Identity، وانتبه إلى ما تحذر منه OWASP، أي ألا يتحول القفل إلى طريقة لحجب الخدمة عن المستخدمين الحقيقيين، لذلك اجعله مؤقتاً، ومعه حد للمعدل على مستوى ال Reverse Proxy.
- الكود الأول يفترض أن اسم المستخدم هو البريد، والثاني كذلك، فإذا كان التطبيق يفصل بينهما فابحث عن المستخدم أولاً ولكن أعد الرسالة نفسها في كل الحالات.

### كيف تمنعه؟

- **المصادقة متعددة العوامل MFA:** وأفضل منها الدخول دون كلمة مرور، كما في دليل [Passkeys وFIDO2](https://arabroot.io/articles/%D8%A7%D9%84%D8%AF%D8%AE%D9%88%D9%84-%D8%AF%D9%88%D9%86-%D9%83%D9%84%D9%85%D8%A9-%D9%85%D8%B1%D9%88%D8%B1-passkeys-%D9%88-fido2/)، لأن المفتاح لا يعطى للموقع المزيف أصلاً.
- **سياسة كلمات مرور حديثة:** تحيل OWASP إلى [NIST SP 800-63B](https://pages.nist.gov/800-63-4/sp800-63b.html?ref=arabroot.io)، أي طول كاف، وفحص كلمة المرور الجديدة مقابل قوائم المسرب، وعدم إجبار الناس على تغييرها دورياً إلا عند الشك في تسريب.
- **لا تنشر التطبيق بكلمات مرور افتراضية:** وخصوصاً لحساب المدير، فاجعل الإعداد الأول يطلب كلمة مرور جديدة.
- **جلسة يديرها السيرفر:** معرف عشوائي جديد بعد الدخول، في Cookie آمنة، يلغى عند الخروج وبعد مدة الخمول، كما في دليل [الجلسات وJWT](https://arabroot.io/articles/%D8%A7%D9%84%D8%AC%D9%84%D8%B3%D8%A7%D8%AA-%D9%88%D9%85%D9%84%D9%81%D8%A7%D8%AA-%D8%AA%D8%B9%D8%B1%D9%8A%D9%81-%D8%A7%D9%84%D8%A7%D8%B1%D8%AA%D8%A8%D8%A7%D8%B7-%D9%88-jwt-%D9%84%D9%84%D9%85%D8%A8%D8%AA%D8%AF%D8%A6%D9%8A%D9%86/)، ومع JWT تحقق من الحقلين `aud` و`iss` والصلاحيات.
- **لا تكتب المصادقة بنفسك:** تنصح OWASP باستخدام نظام جاهز موثوق للهوية والجلسات، وقد شرحنا البروتوكولات في دليل [OAuth وOpenID Connect](https://arabroot.io/articles/%D8%B4%D8%B1%D8%AD-oauth-%D9%88-openid-connect-%D9%84%D9%84%D9%85%D8%A8%D8%AA%D8%AF%D8%A6%D9%8A%D9%86/).

### كيف تكتشفه؟

أداة SAST تجد كلمات المرور المكتوبة في الكود، وفحص الأسرار يجد بيانات الدخول المسربة في المستودع، وأداة DAST تفحص خصائص Cookie الجلسة ورسائل الدخول، أما محاولات التخمين الفعلية فتظهر في السجلات، وقد شرحنا حد المعدل والحظر التلقائي في قسم [الحد من معدل الطلبات Rate Limiting](https://arabroot.io/articles/%D8%AD%D9%85%D8%A7%D9%8A%D8%A9-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D8%B9%D9%84%D9%89-%D9%85%D8%B3%D8%AA%D9%88%D9%89-http/#rate-limiting).

## A08:2025 أخطاء سلامة البرمجيات والبيانات Software or Data Integrity Failures

### ما هو بلغة بسيطة؟

تقول [صفحة A08](https://top10.owasp.org/2025/A08%5F2025-Software%5For%5FData%5FIntegrity%5FFailures/?ref=arabroot.io) إن هذه الفئة تتعلق بكود وبنية تحتية لا تحمي من أن يعامل كود أو بيانات غير موثوقة على أنها موثوقة وصحيحة، وإنها تعمل على مستوى أدنى من فئة سلسلة التوريد. ومن أمثلتها: تحميل إضافات أو مكتبات من مصادر وشبكات توزيع محتوى CDN غير موثوقة، وتحديث تلقائي Auto-update يثبت دون التحقق من التوقيع، وخط CI يسحب ملفات دون أن يتحقق منها، وفك التسلسل غير الآمن Insecure Deserialization، أي أن يستقبل التطبيق كائناً مسلسلاً Serialized Object من المستخدم فيعيد بناءه كما هو.

### المثال على تطبيق الفواتير

سلة الخدمات في التطبيق محفوظة في Cookie، والكود يقرؤها بالوحدة `pickle` في Python، و[توثيق pickle](https://docs.python.org/3/library/pickle.html?ref=arabroot.io) يقول بوضوح إن الوحدة غير آمنة، وإن بيانات pickle المعدة بطريقة معينة تستطيع تنفيذ كود عند فكها، فلا تفك إلا بيانات تثق بها:

```python
# Vulnerable: rebuilds whatever object the client sends
import base64, pickle

cart = pickle.loads(base64.b64decode(request.cookies["cart"]))
```

والشكل المصلح يستخدم صيغة بيانات فقط مثل JSON، ويوقع القيمة بمفتاح على السيرفر حتى يكتشف أي تعديل، وهو ما يقترحه توثيق pickle نفسه حين يذكر التوقيع بـ hmac:

```python
# Fixed: data-only format, signed by the server, checked before use
import base64, hashlib, hmac, json, os

KEY = os.environ["CART_SIGNING_KEY"].encode()

def load_cart(cookie: str) -> dict:
    payload, _, signature = cookie.partition(".")
    expected = hmac.new(KEY, payload.encode(), hashlib.sha256).hexdigest()
    if not hmac.compare_digest(signature, expected):
        raise ValueError("cart cookie was modified")
    return json.loads(base64.urlsafe_b64decode(payload))
```

في الكود أعلاه لاحظ التالي:

- JSON يعيد قيماً وقوائم وقواميس فقط، ولا يستطيع أن يبني كائناً من أي كلاس، وهذا هو الفرق الجوهري مع pickle، ومثله في Java تجنب `ObjectInputStream` على بيانات من المستخدم، وفي .NET تجنب `BinaryFormatter` الذي تقول Microsoft في [دليلها الأمني](https://learn.microsoft.com/en-us/dotnet/standard/serialization/binaryformatter-security-guide?ref=arabroot.io) إنه غير آمن ولا يمكن جعله آمناً، وإن تنفيذه المدمج يرمي استثناء عند استخدامه بدءاً من .NET 9.
- الدالة `hmac.compare_digest` تقارن في زمن ثابت، والسبب ألا يعرف المهاجم من زمن الرد كم حرفاً صحيحاً في التوقيع.
- الحل الأبسط في أغلب التطبيقات ألا تخزن السلة في المتصفح أصلاً، وإنما على السيرفر مربوطة بالجلسة.

والفكرة نفسها في ملفات JavaScript التي تحملها من CDN، فالخاصية `integrity` تجعل المتصفح يرفض الملف إذا تغير محتواه عن الهاش الذي حددته، كما في [توثيق Subresource Integrity في MDN](https://developer.mozilla.org/en-US/docs/Web/Security/Subresource%5FIntegrity?ref=arabroot.io):

```html
<script src="https://cdn.example.com/chart.min.js"
        integrity="sha384-<hash of the exact file you reviewed>"
        crossorigin="anonymous"></script>
```

### كيف تمنعه؟

- **التوقيع الرقمي Digital Signature:** تحقق من توقيع البرمجيات والتحديثات وال Images قبل تشغيلها.
- **مستودعات موثوقة:** أن تسحب npm وMaven من مستودعات موثوقة، ومع الخطورة الأعلى مستودع داخلي مفحوص.
- **مراجعة التغييرات:** على الكود والإعدادات وخط CI، حتى لا يدخل كود خبيث دون أن يراه أحد.
- **لا تقبل بيانات مسلسلة غير موقعة:** من عميل غير موثوق، كما في المثال أعلاه، والتفاصيل في [OWASP Deserialization Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Deserialization%5FCheat%5FSheet.html?ref=arabroot.io).

### كيف تكتشفه؟

أداة SAST تجد استدعاء `pickle.loads` و`ObjectInputStream` على بيانات من الطلب، وفحص خط البناء يتأكد من التوقيع ومصدر البناء Provenance، كما في قسم الدفاعات من دليل [أمن سلسلة التوريد](https://arabroot.io/articles/%D8%A7%D9%85%D9%86-%D8%B3%D9%84%D8%B3%D9%84%D8%A9-%D8%A7%D9%84%D8%AA%D9%88%D8%B1%D9%8A%D8%AF-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D8%A9-%D9%84%D9%84%D9%85%D8%A8%D8%AA%D8%AF%D8%A6%D9%8A%D9%86/) ومقال [خط CI/CD آمن من البداية للنهاية](https://arabroot.io/articles/%D8%AE%D8%B7-ci-cd-%D8%A7%D9%85%D9%86-%D9%85%D9%86-%D8%A7%D9%84%D8%A8%D8%AF%D8%A7%D9%8A%D8%A9-%D9%84%D9%84%D9%86%D9%87%D8%A7%D9%8A%D8%A9/).

## A09:2025 أخطاء السجلات والتنبيه Security Logging and Alerting Failures

### ما هو بلغة بسيطة؟

تقول [صفحة A09](https://top10.owasp.org/2025/A09%5F2025-Security%5FLogging%5Fand%5FAlerting%5FFailures/?ref=arabroot.io) إنه دون سجلات ومراقبة لا يمكن اكتشاف الهجمات والاختراقات، ودون تنبيه يصعب جداً أن تستجيب بسرعة. ومن صورها: أحداث مهمة لا تسجل، مثل الدخول الفاشل والعمليات المالية الكبيرة، أو تسجيل الدخول الناجح فقط دون الفاشل، وسجلات لا يراقبها أحد، وسجلات محفوظة على السيرفر نفسه فقط، وفحص DAST أو اختبار اختراق كامل يمر دون أن يطلق تنبيهاً واحداً، وتسجيل بيانات حساسة لا يجب أن تسجل، وسجلات غير مرمزة تسمح بحقن السجلات Log Injection، وكثرة التنبيهات الخاطئة حتى يتجاهلها الفريق.

### المثال على تطبيق الفواتير

كود الدخول يكتب سطراً عند النجاح فقط، وفيه كلمة المرور، ولا يكتب شيئاً عند الفشل، والمثال التالي بلغة Java مع SLF4J:

```java
// Vulnerable: secret in the log, failures are invisible
if (authenticated) {
    log.info("login " + email + " password=" + password);
}
```

```java
// Fixed: both outcomes, no secrets, placeholders and a structured (JSON) appender
if (authenticated) {
    log.info("login_succeeded user={} ip={}", userId, clientIp);
} else {
    log.warn("login_failed email={} ip={}", email, clientIp);   // counted by an alert rule
}
```

في الكود أعلاه لاحظ التالي:

- كلمة المرور والتوكنات وأرقام البطاقات لا تدخل السجل أبداً، لأن السجل يقرؤه أشخاص وأنظمة أكثر بكثير ممن يقرأ قاعدة البيانات، وقد شرحنا القائمة في قسم [ما لا يدخل السجل أبداً](https://arabroot.io/articles/%D8%A7%D9%84%D8%B3%D8%AC%D9%84%D8%A7%D8%AA-logging-%D9%84%D9%84%D9%85%D8%B7%D9%88%D8%B1%D9%8A%D9%86-%D9%88%D9%85%D8%AF%D9%8A%D8%B1%D9%8A-%D8%A7%D9%84%D8%B3%D9%8A%D8%B1%D9%81%D8%B1%D8%A7%D8%AA/#never-log).
- القيمة `email` جاءت من المستخدم، وإذا كتبت بالدمج في سطر نصي فقد تحتوي على سطر جديد يزور سطراً كاملاً في السجل، أما مع مخرج منظم JSON فتصبح القيمة حقلاً مرمزاً، كما في قسم [حقن السجلات Log Injection](https://arabroot.io/articles/%D8%A7%D9%84%D8%B3%D8%AC%D9%84%D8%A7%D8%AA-logging-%D9%84%D9%84%D9%85%D8%B7%D9%88%D8%B1%D9%8A%D9%86-%D9%88%D9%85%D8%AF%D9%8A%D8%B1%D9%8A-%D8%A7%D9%84%D8%B3%D9%8A%D8%B1%D9%81%D8%B1%D8%A7%D8%AA/#log-injection).
- السطر الذي لا يقرؤه أحد لا يحمي أحداً، لذلك فالمهم هو قاعدة التنبيه التي تقول مثلاً: أكثر من خمسين فشلاً في الدقيقة من عنوان واحد يرسل إشعاراً.

### كيف تمنعه؟

- **سجل كل ضابط أمني:** تطلب OWASP تسجيل فشل الدخول والتحكم في الوصول والتحقق من المدخلات مع سياق كاف لمعرفة الحساب، وحفظه مدة كافية للتحقيق لاحقاً.
- **سجل تدقيق Audit Trail لا يقبل التعديل:** للعمليات المهمة، مثل جدول يقبل الإضافة فقط Append-only، كما في دليل [سجل التدقيق Audit Trail](https://arabroot.io/articles/%D8%B3%D8%AC%D9%84-%D8%A7%D9%84%D8%AA%D8%AF%D9%82%D9%8A%D9%82-audit-trail-%D9%85%D9%86-%D9%81%D8%B9%D9%84-%D9%85%D8%A7%D8%B0%D8%A7-%D9%88%D9%85%D8%AA%D9%89/).
- **جمع مركزي وتنبيه:** السجل يخرج من السيرفر إلى نظام مركزي له لوحات وتنبيهات، كما في دليل [السجلات Logging للمطورين ومديري السيرفرات](https://arabroot.io/articles/%D8%A7%D9%84%D8%B3%D8%AC%D9%84%D8%A7%D8%AA-logging-%D9%84%D9%84%D9%85%D8%B7%D9%88%D8%B1%D9%8A%D9%86-%D9%88%D9%85%D8%AF%D9%8A%D8%B1%D9%8A-%D8%A7%D9%84%D8%B3%D9%8A%D8%B1%D9%81%D8%B1%D8%A7%D8%AA/).
- **الطعم Honeytokens:** تقترح OWASP حسابات أو سجلات وهمية لا يستخدمها أحد في العمل العادي، فأي وصول إليها يطلق تنبيهاً شبه خال من الإنذارات الخاطئة.
- **خطة استجابة Incident Response:** مكتوبة قبل الحادثة، ومعروف فيها من يستلم التنبيه.

### كيف تكتشفه؟

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

## A10:2025 سوء التعامل مع الحالات الاستثنائية Mishandling of Exceptional Conditions

### ما هو بلغة بسيطة؟

هذه الفئة جديدة في 2025، وتقول [صفحة A10](https://top10.owasp.org/2025/A10%5F2025-Mishandling%5Fof%5FExceptional%5FConditions/?ref=arabroot.io) إنها تحدث عندما يفشل البرنامج في منع حالة غير عادية أو في اكتشافها أو في الاستجابة لها، فيؤدي ذلك إلى توقف أو سلوك غير متوقع أو ثغرة. ومن نقاط الضعف التي تذكرها: رسالة خطأ فيها معلومات حساسة، وعدم التعامل مع معامل ناقص، والفشل المفتوح Failing Open أي أن يسمح النظام بالعملية عندما يفشل الفحص، ومعاملة مالية تتوقف في منتصفها دون أن ترجع خطواتها.

### المثال على تطبيق الفواتير

التطبيق يسأل خدمة صلاحيات منفصلة قبل فتح المستند، والمطور لا يريد أن يتوقف العمل إذا تعطلت الخدمة، فيكتب الكود التالي بلغة C#:

```csharp
// Vulnerable: fails open, an outage of the policy service grants access to everyone
bool allowed;
try
{
    allowed = await _policy.CanReadAsync(userId, documentId);
}
catch (Exception)
{
    allowed = true;   // "do not block users when the policy service is down"
}
```

```csharp
// Fixed: fails closed, logs the error, and the user gets a clear answer
bool allowed;
try
{
    allowed = await _policy.CanReadAsync(userId, documentId);
}
catch (Exception ex)
{
    _logger.LogError(ex, "Policy check failed for document {DocumentId}", documentId);
    return StatusCode(503);   // no answer from the policy service means no access
}
if (!allowed) return NotFound();
```

في الكود أعلاه لاحظ التالي:

- الكود الأول يبدو لطيفاً مع المستخدم، لكن من يستطيع أن يجعل خدمة الصلاحيات تتعطل أو تبطئ حتى تنتهي مهلتها Timeout قد حصل على صلاحية الجميع، ولهذا تقول صفحة A09 «Always fail closed».
- الخطأ يسجل مرة واحدة مع تفاصيله، والمستخدم يرى رداً عاماً دون Stack Trace، وهذا الرابط بين A10 وA02 وA09.
- وفي العمليات متعددة الخطوات، مثل خصم من حساب وإضافة إلى آخر وتسجيل العملية، تطلب OWASP أن ترجع المعاملة Transaction كلها عند أي خطأ بدل محاولة إكمالها من منتصفها، وفي EF Core مثلاً المعاملة التي لم ينفذ عليها `CommitAsync` ترجع عند التخلص منها.

### كيف تمنعه؟

- **توقع الأسوأ:** التقط الخطأ في المكان الذي يحدث فيه وتعامل معه هناك، ومع ذلك ضع معالجاً عاماً Global Exception Handler لما فاتك، كما في [OWASP Error Handling Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Error%5FHandling%5FCheat%5FSheet.html?ref=arabroot.io).
- **الفشل المغلق Fail Closed:** في كل فحص أمني، وكذلك رجوع المعاملة كاملة.
- **حدود في كل مكان:** تقول الصفحة إنه لا يجب أن يكون شيء في تقنية المعلومات بلا حدود، فضع حداً للمعدل Rate Limit وحصصاً Quotas ومهلاً Timeouts، ومنها حدود حجم الملفات التي شرحناها في دليل [حدود حجم رفع الملفات](https://arabroot.io/articles/%D8%AD%D8%AF%D9%88%D8%AF-%D8%AD%D8%AC%D9%85-%D8%B1%D9%81%D8%B9-%D8%A7%D9%84%D9%85%D9%84%D9%81%D8%A7%D8%AA/).
- **طريقة واحدة في المؤسسة كلها:** معالجة الأخطاء في مكان واحد وبالطريقة نفسها، لأن ذلك يسهل مراجعتها.

### كيف تكتشفه؟

أداة SAST تجد كتل `catch` الفارغة والاستثناءات التي تبتلع، ومراجعة الكود تجد الفشل المفتوح لأنه قرار وليس خطأ في الكتابة، واختبارات الضغط Stress Tests واختبار الاختراق تكشف ما يحدث تحت الحمل وعند انقطاع الشبكة، وقد شرحنا اختبار الحمل في دليل [اختبار الأحمال والضغط Load وStress Testing](https://arabroot.io/articles/%D8%A7%D8%AE%D8%AA%D8%A8%D8%A7%D8%B1-%D8%A7%D9%84%D8%A7%D8%AD%D9%85%D8%A7%D9%84-%D9%88%D8%A7%D9%84%D8%B6%D8%BA%D8%B7-load-%D9%88-stress-testing-%D9%84%D9%84%D9%85%D8%A8%D8%AA%D8%AF%D8%A6%D9%8A%D9%86/).

## أين تكتشف كل خطر؟ في التصميم Design والكود Code والبناء Build والتشغيل Runtime

بعد أن مررنا على الفئات العشر، لاحظ أن كل فئة لها مكان تظهر فيه بسهولة وأماكن لا تظهر فيها أبداً، والصورة التالية تجمع ذلك في جدول واحد، وهي تقدير تحريري منا مبني على أقسام الوقاية في صفحات OWASP وليس بيانات منشورة:

![جدول صفوفه الفئات من A01 إلى A10 وأعمدته Design وCode وBuild وRuntime، وفيه دائرة ممتلئة للمكان الرئيسي للاكتشاف ودائرة فارغة لما يساعد جزئياً وخط لما لا يفيد، فمثلاً A05 Injection ممتلئة في Code وRuntime، وA06 Insecure Design ممتلئة في Design فقط، وA03 ممتلئة في Build وRuntime، وA01 ممتلئة في Code وRuntime](https://arabroot.io/content/images/2026/10/owasp-top10-06-where-caught.webp)

تقدير تحريري لمكان اكتشاف كل فئة، والملاحظة الأهم أن عمود التشغيل لا يغني عن الأعمدة التي قبله

وفي الصورة أعلاه لاحظ التالي:

- لا توجد أداة واحدة تغطي العمود كله، ولا يوجد عمود يغطي القائمة كلها، وهذا ما رأيناه عملياً في تجربة مقال [DevSecOps للمبتدئين](https://arabroot.io/articles/devsecops-%D9%84%D9%84%D9%85%D8%A8%D8%AA%D8%AF%D8%A6%D9%8A%D9%86-sast-%D9%88-dast-%D9%88-sca/) حين فحصت أربع أدوات التطبيق نفسه فرأت كل منها جزءاً منه.
- الفئتان A01 وA06، أي الأولى والسادسة، تحتاجان إنساناً يعرف ما يجب أن يحدث، لأن الأداة لا تعرف قواعد عملك.
- الفئات التي تجيدها الأدوات، مثل الحقن والمكتبات والإعدادات، هي التي يجب أن تعمل آلياً في كل طلب دمج Pull Request، حتى يتفرغ الناس للفئات التي لا تجيدها الأدوات.

## كيف تستخدم القائمة في فريقك، وكيف لا تستخدمها؟

الاستخدام الصحيح للقائمة أن تكون لغة مشتركة في الفريق، فعندما يقول أحدهم في مراجعة الكود «هذا A01» يفهم الجميع أن المشكلة صلاحية ناقصة، وأن تكون منهج تدريب أول للمطورين الجدد، وأن تسأل بها بعد نمذجة التهديدات «هل نسينا فئة مشهورة؟». أما الاستخدام الخاطئ فهو أن تتحول إلى قائمة تحقق للامتثال Compliance، فيكتب الفريق «فحصنا العشرة» ويعتبر التطبيق آمناً، والسبب أن القائمة كما تقول OWASP نقطة بداية وليست قائمة كاملة، وأن كل فئة فيها عشرات نقاط الضعف التي لا تختبر بسؤال واحد.

وإذا أردت متطلبات تتحقق منها فعلاً، فالخطوة التالية هي معيار ASVS، وفيه متطلبات مرقمة لكل مستوى، وقد خصصنا له مقال [متطلبات الأمان ومراجعة الكود مع OWASP ASVS](https://arabroot.io/articles/%D9%85%D8%AA%D8%B7%D9%84%D8%A8%D8%A7%D8%AA-%D8%A7%D9%84%D8%A7%D9%85%D8%A7%D9%86-%D9%88%D9%85%D8%B1%D8%A7%D8%AC%D8%B9%D8%A9-%D8%A7%D9%84%D9%83%D9%88%D8%AF-%D9%85%D8%B9-owasp-asvs/)، ومعه قائمة مراجعة لكل Pull Request.

## مسار القراءة Reading Path في مرحلة أمن التطبيقات AppSec

هذا المقال يعطيك الخريطة، والمقالات التالية في المرحلة نفسها تتعمق في كل جزء، بهذا الترتيب: الثغرات بالتجربة، ثم واجهات API، ثم البرمجة الآمنة بأمثلة في كل لغة، ثم التشفير للمطورين، ثم المتطلبات ومراجعة الكود:

[![](https://arabroot.io/content/images/2026/10/web-vulns-lab-cover-cover.webp)دليلثغرات الويب بالتجربة: تطبيق نكسره ثم نصلحهنرى أثر أشهر ثغرات الويب على متجر صغير على جهازك، ثم السطر المسؤول عن كل ثغرة، ثم الإصلاح والاختبار الذي يثبته.](https://arabroot.io/articles/%D8%AB%D8%BA%D8%B1%D8%A7%D8%AA-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D8%A8%D8%A7%D9%84%D8%AA%D8%AC%D8%B1%D8%A8%D8%A9-sql-injection-%D9%88-xss-%D9%88-ssrf/)[![](https://arabroot.io/content/images/2026/10/api-security-cover-cover.webp)دليلأمن ال API بالأمثلة مع OWASP API Security Top 10أشهر عشرة مخاطر في واجهات API كما ترتبها OWASP، ولكل خطر مثال لكود ضعيف وكيف تصلحه وتختبره.](https://arabroot.io/articles/%D8%A7%D9%85%D9%86-%D9%88%D8%A7%D8%AC%D9%87%D8%A7%D8%AA-api-%D9%85%D8%B9-owasp-api-security-top-10/)[![](https://arabroot.io/content/images/2026/10/secure-coding-cover-cover.webp)دليلالبرمجة الآمنة Secure Coding بأمثلة من أربع لغاتكيف تكتب الكود الذي يتعامل مع مدخلات المستخدم والملفات والأخطاء بحيث لا يحتاج إصلاحاً أمنياً لاحقاً، بأمثلة في أربع لغات.](https://arabroot.io/articles/%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%A7%D9%84%D8%A7%D9%85%D9%86%D8%A9-secure-coding-%D9%84%D9%84%D9%85%D8%B7%D9%88%D8%B1%D9%8A%D9%86/)[![](https://arabroot.io/content/images/2026/10/crypto-for-devs-cover-cover.webp)دليلالتشفير للمطورين: ماذا تستخدم ولماذا لا تخترع خوارزميتكأي هاش تستخدم لكلمات المرور، ومتى تحتاج التشفير المتماثل أو غير المتماثل، وأين تحفظ المفاتيح بأمان في تطبيقك.](https://arabroot.io/articles/%D8%A7%D9%84%D8%AA%D8%B4%D9%81%D9%8A%D8%B1-%D9%84%D9%84%D9%85%D8%B7%D9%88%D8%B1%D9%8A%D9%86-%D8%A7%D9%84%D9%87%D8%A7%D8%B4-%D9%88%D9%83%D9%84%D9%85%D8%A7%D8%AA-%D8%A7%D9%84%D9%85%D8%B1%D9%88%D8%B1-%D9%88%D8%A7%D9%84%D9%85%D9%81%D8%A7%D8%AA%D9%8A%D8%AD/)[![](https://arabroot.io/content/images/2026/10/asvs-review-cover-cover.webp)دليلOWASP ASVS ومراجعة الكود الأمنية لكل Pull Requestكيف تكتب متطلبات أمان يمكن اختبارها مع OWASP ASVS، وتراجع كل طلب دمج أمنياً في عشرين دقيقة بقائمة جاهزة.](https://arabroot.io/articles/%D9%85%D8%AA%D8%B7%D9%84%D8%A8%D8%A7%D8%AA-%D8%A7%D9%84%D8%A7%D9%85%D8%A7%D9%86-%D9%88%D9%85%D8%B1%D8%A7%D8%AC%D8%B9%D8%A9-%D8%A7%D9%84%D9%83%D9%88%D8%AF-%D9%85%D8%B9-owasp-asvs/)

وقبلها أو بجانبها، مقالان يكملان الصورة، الأول عن التصميم قبل الكود، والثاني عن الفحوص الآلية في خط CI/CD:

[![](https://arabroot.io/content/images/2026/10/threat-modeling-cover-cover.webp)دليلنمذجة التهديدات Threat Modeling للمبتدئينكيف تسأل ما الذي قد يسوء في تصميم تطبيقك قبل أن تكتب الكود، وتقرر لكل تهديد هل تصلحه أو تقبله، مع قالب جاهز للنسخ.](https://arabroot.io/articles/%D9%86%D9%85%D8%B0%D8%AC%D8%A9-%D8%A7%D9%84%D8%AA%D9%87%D8%AF%D9%8A%D8%AF%D8%A7%D8%AA-threat-modeling-%D9%84%D9%84%D9%85%D8%A8%D8%AA%D8%AF%D8%A6%D9%8A%D9%86/)[![](https://arabroot.io/content/images/2026/10/devsecops-cover-cover.webp)دليلDevSecOps للمبتدئين: الأمن داخل خط CI/CD ومتى يعمل كل فحصما الذي يجده كل فحص أمني في خط CI/CD وما الذي يفوته، وكيف ترتب نتائجه حتى تصل إلى قرار بدل قائمة طويلة.](https://arabroot.io/articles/devsecops-%D9%84%D9%84%D9%85%D8%A8%D8%AA%D8%AF%D8%A6%D9%8A%D9%86-sast-%D9%88-dast-%D9%88-sca/)

وهذه المقالات التي تملك كل فئة من الفئات وتشرحها بالتفصيل، مرتبة حسب الفئة:

[![](https://arabroot.io/content/images/2026/10/authorization-cover-cover.webp)دليلAuthorization: كيف تجمع قرارات الصلاحيات في مكان واحدلماذا تتحول شروط الصلاحيات المتفرقة في الكود إلى ثغرات، وكيف تنقل القرار إلى محرك سياسات واحد.](https://arabroot.io/articles/%D8%A7%D9%84%D8%B5%D9%84%D8%A7%D8%AD%D9%8A%D8%A7%D8%AA-%D8%A7%D9%84%D9%85%D8%B1%D9%83%D8%B2%D9%8A%D8%A9-authorization-rbac-%D9%88-rebac/)[![](https://arabroot.io/content/images/2026/10/multi-tenancy-practice-cover-cover.webp)دليلتطبيق SaaS متعدد المستأجرين عملياً مع Row-Level Securityنبني على PostgreSQL تطبيق SaaS يعزل كل مستأجر Tenant عن غيره بسياسات Row-Level Security، ونرى أين تتسرب البيانات رغم ذلك.](https://arabroot.io/articles/%D8%A8%D9%86%D8%A7%D8%A1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-saas-%D9%85%D8%AA%D8%B9%D8%AF%D8%AF-%D8%A7%D9%84%D9%85%D8%B3%D8%AA%D8%A7%D8%AC%D8%B1%D9%8A%D9%86-%D8%B9%D9%85%D9%84%D9%8A%D8%A7/)[![](https://arabroot.io/content/images/2026/10/security-headers-cover-cover.webp)دليلHSTS وCSP: ترويسات الأمان التي يحتاجها كل تطبيقما الذي تطلبه كل ترويسة أمان من المتصفح، ولماذا يصعب التراجع عن HSTS، وكيف تبني سياسة CSP لا تكسر تطبيقك.](https://arabroot.io/articles/%D8%AA%D8%B1%D9%88%D9%8A%D8%B3%D8%A7%D8%AA-%D8%A7%D9%84%D8%A3%D9%85%D8%A7%D9%86-hsts-%D9%88-csp/)[![](https://arabroot.io/content/images/2026/10/supply-chain-cover-cover.webp)دليلأمن سلسلة التوريد البرمجية Software Supply Chain للمبتدئينكل ما بين كود غيرك وسيرفرك قد يحمل كود المهاجم، وهنا تعرف التهديدات الحقيقية بحوادث موثقة والدفاع المناسب لكل حلقة.](https://arabroot.io/articles/%D8%A7%D9%85%D9%86-%D8%B3%D9%84%D8%B3%D9%84%D8%A9-%D8%A7%D9%84%D8%AA%D9%88%D8%B1%D9%8A%D8%AF-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D8%A9-%D9%84%D9%84%D9%85%D8%A8%D8%AA%D8%AF%D8%A6%D9%8A%D9%86/)[![](https://arabroot.io/content/images/2026/10/sessions-cookies-jwt-cover-cover.webp)دليلكيف يتذكرك الموقع بعد تسجيل الدخول؟ الجلسات وJWTبروتوكول HTTP لا يتذكر أحداً، فكيف يبقى المستخدم مسجلاً بين الصفحات، ومتى تختار الجلسة على السيرفر ومتى تختار JWT.](https://arabroot.io/articles/%D8%A7%D9%84%D8%AC%D9%84%D8%B3%D8%A7%D8%AA-%D9%88%D9%85%D9%84%D9%81%D8%A7%D8%AA-%D8%AA%D8%B9%D8%B1%D9%8A%D9%81-%D8%A7%D9%84%D8%A7%D8%B1%D8%AA%D8%A8%D8%A7%D8%B7-%D9%88-jwt-%D9%84%D9%84%D9%85%D8%A8%D8%AA%D8%AF%D8%A6%D9%8A%D9%86/)[![](https://arabroot.io/content/images/2026/10/passkeys-cover-cover.webp)دليلالدخول دون كلمة مرور: شرح Passkeys وWebAuthnلماذا لا تحميك رموز SMS وTOTP من التصيد الحديث، وكيف تحل Passkeys المشكلة بمفتاح خاص لا يغادر جهازك.](https://arabroot.io/articles/%D8%A7%D9%84%D8%AF%D8%AE%D9%88%D9%84-%D8%AF%D9%88%D9%86-%D9%83%D9%84%D9%85%D8%A9-%D9%85%D8%B1%D9%88%D8%B1-passkeys-%D9%88-fido2/)[![](https://arabroot.io/content/images/2026/10/logging-basics-cover-cover.webp)دليلالسجلات Logging للمطورين: ماذا تسجل وماذا لا تسجلكيف تكتب سجلات Logs تساعدك على فهم ما حدث في الإنتاج، وما الذي لا يدخل السجل أبداً، وكيف تجمعها في مكان واحد.](https://arabroot.io/articles/%D8%A7%D9%84%D8%B3%D8%AC%D9%84%D8%A7%D8%AA-logging-%D9%84%D9%84%D9%85%D8%B7%D9%88%D8%B1%D9%8A%D9%86-%D9%88%D9%85%D8%AF%D9%8A%D8%B1%D9%8A-%D8%A7%D9%84%D8%B3%D9%8A%D8%B1%D9%81%D8%B1%D8%A7%D8%AA/)[![](https://arabroot.io/content/images/2026/10/audit-trail-cover-cover.webp)دليلAudit Trail: كيف تبني سجل تدقيق لا يقبل العبثكيف تصمم سجلاً يجيب عن سؤال من غير هذه الصلاحية ومتى، وتحميه من الحذف والتعديل بعد كتابته.](https://arabroot.io/articles/%D8%B3%D8%AC%D9%84-%D8%A7%D9%84%D8%AA%D8%AF%D9%82%D9%8A%D9%82-audit-trail-%D9%85%D9%86-%D9%81%D8%B9%D9%84-%D9%85%D8%A7%D8%B0%D8%A7-%D9%88%D9%85%D8%AA%D9%89/)

## أخطاء شائعة Common Mistakes

- **الخلط بين المصادقة والتفويض:** `[Authorize]` أو `@login_required` تعني أن المستخدم مسجل، ولا تعني أن السجل الذي يطلبه له، وهذا أصل الفئة الأولى.
- **الفحص في الواجهة فقط:** إخفاء الزر أو تعطيل الحقل أو وضع حد في نموذج HTML، والطلب يمكن إرساله دون الواجهة.
- **تنظيف المدخلات بدل فصلها:** قائمة حروف ممنوعة أو استبدال علامات الاقتباس، والحل الصحيح الاستعلام ذو المعاملات وترميز المخرجات حسب السياق.
- **إعداد التطوير في الإنتاج:** صفحات الخطأ التفصيلية، والحسابات التجريبية، والمنافذ المفتوحة لأنها «مؤقتة».
- **الفشل المفتوح باسم تجربة المستخدم:** السماح بالعملية عندما يتعطل الفحص، فيتحول كل عطل إلى ثغرة.
- **سجلات لا يقرؤها أحد:** أو سجلات فيها كلمات المرور والتوكنات.
- **اعتبار القائمة معياراً للامتثال:** «فحصنا OWASP Top 10» ليست شهادة أمان، فاستخدم ASVS للمتطلبات واختبار الاختراق للتحقق.
- **الاكتفاء بأداة واحدة:** كل أداة ترى طبقة، والفئتان الأولى والسادسة لا تراهما أداة تقريباً.

## قائمة تحقق Checklist لكل ميزة جديدة

- هل يفحص السيرفر ملكية كل سجل في كل Endpoint، مع اختبار آلي يرسل طلب مستخدم آخر ويتوقع الرفض؟ (A01)
- هل يعمل الإنتاج بإعدادات الإنتاج، فلا توجد صفحات خطأ تفصيلية ولا حسابات افتراضية، وترويسات الأمان موجودة، والمنافذ الداخلية مربوطة على 127.0.0.1؟ (A02)
- هل ملف القفل محفوظ في Git، والتثبيت في CI من ملف القفل فقط، وفحص SCA يعمل في كل طلب دمج؟ (A03)
- هل البيانات الحساسة مصنفة ومشفرة، وكلمات المرور مخزنة بدالة مثل Argon2id، والتوكنات من مولد عشوائي للتشفير؟ (A04)
- هل كل استعلام بالمعاملات، وكل مخرج مرمز حسب السياق، ولا يوجد استدعاء Shell بنص من المستخدم؟ (A05)
- هل سأل أحد «ماذا لو…؟» على هذه الميزة، وهل قواعد العمل مكتوبة على السيرفر؟ (A06)
- هل رسالة الدخول واحدة في كل الحالات، ومع قفل مؤقت أو حد للمعدل، وMFA متاح؟ (A07)
- هل البيانات التي تأتي من العميل بصيغة بيانات فقط وموقعة إن احتجت أن تعود إليك، وال Images والتحديثات موقعة؟ (A08)
- هل يسجل الفشل كما يسجل النجاح، دون أسرار، مع تنبيه يصل إلى شخص معروف؟ (A09)
- هل كل فحص أمني يفشل مغلقاً، وكل معاملة ترجع كاملة عند الخطأ، ولكل مورد حد؟ (A10)

## الخلاصة

وصلنا لنهاية الموضوع، وأهم ما فيه:

- OWASP Top 10 وثيقة توعية بأخطر عشر فئات في تطبيقات الويب، ونسختها الحالية 2025 هي الثامنة، وكل فئة فيها مجموعة من نقاط الضعف CWE، وليست معياراً للتحقق ولا قائمة كاملة.
- تبنى القائمة من بيانات اختبار أكثر من 2.8 مليون تطبيق مع درجات الثغرات المنشورة، ثم يضيف الاستبيان فئتين لا تظهران جيداً في البيانات، وهما في 2025 سلسلة التوريد والسجلات والتنبيه.
- الفئات بالترتيب: Broken Access Control، وSecurity Misconfiguration، وSoftware Supply Chain Failures، وCryptographic Failures، وInjection، وInsecure Design، وAuthentication Failures، وSoftware or Data Integrity Failures، وSecurity Logging and Alerting Failures، وMishandling of Exceptional Conditions.
- في التجربة رأينا أن الفرق بين فحص صلاحيات ناقص ومصلح سطر واحد، وأن الرد الواحد في حالتي «ليس لك» و«غير موجود» مع سطر في السجل يجمع الإصلاح من A01 وA09 معاً.
- الأدوات تجيد الحقن والمكتبات والإعدادات، أما الصلاحيات والتصميم فتحتاج اختبارات تكتبها أنت ونمذجة تهديدات ومراجعة من إنسان.
- استخدم القائمة لغة مشتركة ومنهج تدريب، وASVS للمتطلبات، والفحوص الآلية في CI لما تجيده الأدوات.

وفي المقالات القادمة بإذن الله سوف نبني تطبيقاً فيه أشهر هذه الثغرات، ونكسره ثم نصلحه واحدة واحدة، بدءاً من حقن SQL وXSS.

## سجل التحديثات

- أكتوبر 2026: كتابة المقال على نسخة OWASP Top 10:2025 من موقعها الرسمي، والتحقق من أسماء الفئات وترتيبها وطريقة بنائها من مقدمة القائمة وصفحات الفئات، وتنفيذ تجربة فحص الصلاحيات بمكتبة Python القياسية على python:3.12-slim (Python 3.12.15) داخل Docker Engine 29.8.0.