قائمة التحقّق الدنيا لأمان تطبيقات Windows

· آخر تحديث: · · تطوير Windows, الأمان, التصميم, C# / .NET, Win32

سجل التعديلات (4 تحديثات، آخر تحديث 3 Sep، 2026)

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

أُضيفت روابط الاستشارة الموجودة في الأصل الياباني (consultation_services). ولم يتغيّر نصّ المقالة نفسه. قراءة النسخة السابقة لهذا التحديث (DOI: 10.5281/zenodo.22240832)
أُعيدَت الترجمة العربية كترجمة كاملة عن النص الياباني الأصلي، وأُضيفَت خريطة المعرفة.
أُعيدت مراجع الأمان المحذوفة في نهاية المقال وفق الأصل الياباني.
أعيدت الترجمة كترجمة كاملة عن النص الياباني الأصلي. كانت النسخة العربية السابقة مختصراً يسقط أبواباً وجداول ورسوم Mermaid وتعليقات الأشكال وFAQ. أُعيدت هذه العناصر وفق الأصل الياباني، والادّعاءات التقنية مطابقة للنسخة اليابانية.
النشر الأول
الاستشهاد بهذا المقال(DOI: 10.5281/zenodo.21621359)

هذا المقال محفوظ على Zenodo. يرد أدناه معرّف DOI الذي يشير دائمًا إلى أحدث نسخة، ومعرّف DOI المثبَّت على النسخة التي تقرؤها.

小村 豪 (2026). قائمة التحقّق الدنيا لأمان تطبيقات Windows. شركة كومورا سوفت ذ.م.م.. https://doi.org/10.5281/zenodo.21621359 https://comcomponent.com/ar/blog/2026/03/14/001-windows-app-security-minimum-checklist/

DOI (أحدث نسخة)
10.5281/zenodo.21621359
DOI (هذه النسخة)
10.5281/zenodo.22279763

تنزيل قائمة التحقّق بصيغة Excel

محتوى هذا الملف هو قائمة التحقّق قبل الإصدار في الفصل 4 نفسها (8 فئات و 32 بنداً). الفرق فقط وجود حقول Status و Notes، ووجود الورقتين Checklist-ja / Checklist-en باليابانية والإنجليزية. للقراءة أثناء التحقّق يكفي الفصل 4، وللتوزيع كسجل مراجعة استخدم نسخة Excel.

حديث أمان تطبيقات Windows يميل فجأة إلى الاتّساع. الثقة الصفرية، و EDR، و SBOM (Software Bill of Materials، قائمة مكوّنات البرمجيات)، وتشغيل الشهادات، وإدارة الثغرات. كلّها مهمّة، غير أنه في العمل اليومي توجد أساسيات لا تريد إسقاطها قبل ذلك.

خصوصاً في تطبيقات كهذه، سدّ تسريبات الأساس يؤثّر أكثر من «الدفاع المتقدّم» أوّلاً.

  • تطبيقات سطح مكتب WPF / WinForms / WinUI
  • تطبيقات Win32 بـ C++ / C#
  • أدوات ربط أجهزة أو ملفات أو قواعد بيانات، وأدوات توزيع داخل المؤسسة
  • تطبيقات أعمال ذات آلية تحديث تلقائي
  • تكوين يشمل خدمات Windows أو ملفات EXE مساعدة

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

مسار هذه المقالةبسياسة سدّ تسريبات الأساس قبل الدفاع المتقدّم، ترتّب المقالة النقاط الدنيا بترتيب التصميم ثم التنفيذ ثم التوزيع ثم التشغيل.قبل ذلكدفاع متقدّم (الثقة الصفرية وغيره)سدّ تسريبات الأساسالتصميمالتنفيذالتوزيعالتشغيل

الشكل 1: بسياسة سدّ تسريبات الأساس قبل الدفاع المتقدّم، ننظر بترتيب التصميم ثم التنفيذ ثم التوزيع ثم التشغيل.

1. الخلاصة أوّلاً

  • ما لا تريد إسقاطه أوّلاً: عدم طلب امتيازات مدير غير لازمة، والتوقيع، وعدم حفظ الأسرار بنصّ صريح، وعدم تعطيل التحقّق من الشهادات.
  • تطبيق Windows يصير مادّة التوزيع نفسها سطح هجوم. أأمن أن تنظر حتى EXE / DLL / MSI / MSIX / مكوّن التحديث التلقائي.
  • ServerCertificateValidationCallback => true، وسلاسل الاتّصال بنصّ صريح، والتحميل الفضفاض بـ LoadLibrary("foo.dll")، وتنفيذ SQL بربط سلاسل، بنود ينبغي تجنّبها حتى على الخطّ الأدنى.
  • إن كانت المعالجة التي تحتاج امتيازات مدير جزءاً فقط، فأأمن فصل ذلك الجزء إلى EXE أو خدمة منفصلة بدل رفع التطبيق كلّه.
  • التطبيق الذي يُوزَّع على Windows أفضل أن يُفكَّر فيه بافتراض التوقيع + طابع زمني. لا يفيد ثقة المستخدم فقط، بل يسهّل أيضاً كشف العبث والشرح التشغيلي.
  • الأسرار عند الحفظ تُوزَّع حسب الاستخدام بين DPAPI / ProtectedData و Credential Locker. على الأقل تريد الخروج من وضعها بنصّ صريح في appsettings.json.
  • السجلات ليست أفضل كلّما كثرت. إن أبقيت الرموز وكلمات المرور وسلاسل الاتّصال والبيانات الشخصية ومتن الطلب كاملاً كما هي، صارت السجلات نفسها بطلة الحادث.

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

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

الشكل 2: الخطّ الأدنى ليس إضافة ميزة، بل عدم إبقاء سلوك افتراضي خطر أو تنفيذ فضفاض.

في المخطّط، يشير الخطّ المتّصل إلى علاقة قائمة دائماً، ويشير الخطّ المتقطّع إلى علاقة مشروطة (شروط قيامها مذكورة في شرح كلّ علاقة في الصفحة التفصيليّة). القائمة الكاملة للعلاقات (المجموع 21، مع الأدلّة ودرجة اليقين) وتعريفات المفاهيم الرئيسة مجمّعة في صفحة تفاصيل خريطة المعرفة (باليابانية). البيانات: JSON-LD / Turtle

2. نطاق هذه المقالة ومعنى «الأدنى»

2.1. النطاق المستهدف

تطبيقات Windows التي تفترضها هذه المقالة من هذا النوع.

  • تطبيقات سطح مكتب WPF / WinForms / WinUI
  • تطبيقات Win32 بـ C++ / C#
  • أدوات توزيع داخل المؤسسة، وأدوات ربط أجهزة، وأدوات مراقبة
  • تكوين يشمل EXE مساعداً وخدمات Windows ومحدِّثاً
  • برمجيات أعمال تُوزَّع كـ EXE / MSI / MSIX

«الأدنى» هنا ليس الشكل النهائي الذي يمرّ في التدقيق، بل بنود إن سقطت وقع الحادث بشكل عادي.

معنى «الأدنى» في هذه المقالةالأدنى في هذه المقالة لا يشير إلى الشكل النهائي الذي يمرّ في التدقيق، بل إلى بنود إن سقطت وقع الحادث بشكل عادي.لا يشير إليه هناهذا ما يشير إليهالشكل النهائي الذي يمرّ في التدقيق«الأدنى» في هذه المقالةبنود إن سقطت وقع الحادث بشكل عادي

الشكل 3: ما يشير إليه «الأدنى» ليس الشكل النهائي للتدقيق، بل البنود التي إن سقطت وقع الحادث بشكل عادي.

نوحّد أيضاً مقدّمات أمثلة الشيفرة. أمثلة C# تفترض .NET 8 فما بعد، وأمثلة C++ تفترض Win32 API. في .NET Framework 4.8 تبقى طريقة التفكير نفسها، غير أن الكتابة الموصى بها تغيّرت في مواضع. المثال الأبرز محيط ServicePointManager في 3.6، حيث صارت المقدّمة في الشيفرة الجديدة استخدام IHttpClientFactory و HttpClient. عند إعادة قراءة كود جيل أقدم انتبه إلى هذا الموضع فقط.

2.2. خارج النطاق

في المقابل نخرج من مركز هذه المقالة أموراً أيضاً.

  • تصميم الثقة الصفرية للمؤسسة كلّها
  • التشغيل الكلّي لـ EDR / SIEM / DLP / MDM
  • تصليب مفصّل لبرامج تشغيل النواة
  • حديث تصميم التشفير من الصفر
  • تحليل تهديد متقدّم أو إجراءات الطبّ الشرعي

أي أننا لا نتناول «سياسات أمان مؤسسية ضخمة»، بل خطّاً أساسياً يصعب على مطوّر تطبيقات Windows إسقاطه بنفسه قبل الإصدار.

رسم خطّ الداخل والخارجالسياسات المؤسسية الضخمة خارج النطاق، والخطّ الأساسي الذي يصعب على مطوّر تطبيقات Windows إسقاطه بنفسه قبل الإصدار هو الداخل.لا نتناولها هناهذا ما نتناولهسياسات مؤسسية ضخمةنطاق هذه المقالةخطّ أساسي يصعب على المطوّر إسقاطه بنفسه

الشكل 4: ما نتناوله ليس سياسات المؤسسة كلّها، بل الخطّ الأساسي الذي يستطيع المطوّر ضبطه بنفسه قبل الإصدار.

3. قائمة تحقّق للنظر أوّلاً

قبل النقاش التفصيلي نضع جدولاً يرى الصورة كلّها. هذا وحده يكفي لتحديد مواضع المراجعة.

3.1. الصورة الكاملة

البند الحدّ الأدنى الرفض النمطي
صلاحيات التشغيل الأساس asInvoker، وفصل المعالجة التي تحتاج رفعاً فقط جعل التطبيق كلّه requireAdministrator
موثوقية مادّة التوزيع توقيع شيفرة لـ EXE / DLL / MSI / MSIX مع طابع زمني التوزيع بلا توقيع
التحديث تثبيت مصدر التحديث وكشف العبث عبر HTTPS والتحقّق من التوقيع التنزيل عبر HTTP ثم الكتابة فوق الملف كما هو
المعلومات السرّيّة عدم وضع سرّ في الشيفرة أو إعداد نصّ صريح، واستخدام DPAPI / Credential Locker وغيرهما وضع مفتاح API أو سلسلة اتّصال بنصّ صريح في ملف الإعداد
الاتّصال استخدام HTTPS وعدم تعطيل التحقّق من الشهادات تخطّي التحقّق من الشهادات دائماً بـ return true
الإدخال الخارجي التحقّق من SQL والملفات و IPC و URI و CSV و JSON وغيرها كلّها التمرير كما هو لأنّه «أداة داخلية»
تحميل DLL مسار مطلق، و SetDefaultDllDirectories، وترتيب بحث آمن إسناد LoadLibrary("foo.dll") إلى الدليل الحالي
السجلات إخفاء الرموز وكلمات المرور و PII، وفصل أخطاء المستخدم عرض تفاصيل الاستثناء أو سلاسل الاتّصال وحفظها كما هي
التبعيات تحديث مستمر لـ SDK و NuGet ووقت تشغيل VC++ وتبعيات OSS التثبيت لسنوات دون تتبّع معلومات الثغرات

3.2. الأساس في الصلاحيات هو asInvoker

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

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

الشكل 5: رفع التطبيق كلّه يجعل كلّ عيب يحمله يُنفَّذ بصلاحيات قوية.

الاتجاه الأساسي كالتالي.

  • تطبيق واجهة المستخدم العادي asInvoker
  • فصل المعالجة التي تحتاج امتيازات مدير إلى عملية أو خدمة منفصلة
  • إجراء الرفع في اللحظة اللازمة فقط
  • التحقّق أيضاً من الإدخال الممرَّر إلى EXE المساعد أو الخدمة

إن كان تطبيق سطح المكتب للعرض والتحرير فقط عادة، ولم تلزم امتيازات المدير إلا للتثبيت أو تغيير إعداد جدار الحماية، فأأمن جمع الجزء الذي يحتاج رفعاً في وسيط (broker) بدل جعل التطبيق كلّه requireAdministrator.

<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
  <security>
    <requestedPrivileges>
      <requestedExecutionLevel level="asInvoker" uiAccess="false" />
    </requestedPrivileges>
  </security>
</trustInfo>

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

فصل المعالجة التي تحتاج رفعاً فقطتطبيق واجهة المستخدم العادي يعمل بـ asInvoker، وتُجمع المعالجة التي تحتاج امتيازات مدير في وسيط عملية أو خدمة منفصلة، ويُجرى الرفع في اللحظة اللازمة فقط.طلب في اللحظة اللازمة فقطتطبيق الواجهة (asInvoker)وسيط (EXE / خدمة منفصلة)تنفيذ المعالجة التي تحتاج رفعاً فقطالتحقّق أيضاً من الإدخال الممرَّر إلى الوسيط

الشكل 6: التشغيل العادي بـ asInvoker وجمع ما يحتاج رفعاً في وسيط يصغّر نصف قطر الحادث.

3.3. توقيع الثنائيات والمُثبِّت

على Windows موثوقية مادّة التوزيع هي ما يحسم. ما يلمسه المستخدم ليس الشيفرة المصدرية، بل EXE و DLL و MSI و MSIX والمحدِّث. إن بقيت بلا توقيع ضعفت الشرح التشغيلي وكشف العبث والاطمئنان عند التوزيع.

ما يلمسه المستخدم هو مادّة التوزيعما يلمسه المستخدم ليس الشيفرة المصدرية بل EXE و DLL والمُثبِّت والمحدِّث، وإن بقيت بلا توقيع ضعف كشف العبث والشرح التشغيلي.ما يلمسه المستخدمEXE / DLLMSI / MSIXالمحدِّثبلا توقيع يضعف كشف العبث والشرح

الشكل 7: سطح الهجوم هو مادّة التوزيع نفسها، وبقاؤها بلا توقيع يفقد سند الموثوقية.

في الحدّ الأدنى، انظر إلى ما يلي.

  • توقيع EXE / DLL / MSI / MSIX
  • توقيع الثنائيات المساعدة المستخدمة في التحديث أيضاً، لا المُثبِّت فقط
  • إرفاق طابع زمني
  • إدخال أجل الشهادة وإجراء التجديد في خطوات الإصدار

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

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

الشكل 8: لا تنهِ عند التوقيع وحده، وأدخل الطابع الزمني أيضاً في خطوات الإصدار.

إن استخدمت MSIX فتوقيع الحزمة مقدّمة. وحتّى مع توزيع MSI / EXE، الأفضل على الأقل توقيع متن المُثبِّت والثنائيات التنفيذية الرئيسة.

3.4. تثبيت مسار التحديث وإدخال كشف العبث

في تطبيقات Windows اليوم، مسار التحديث يُستخدم أطول من التثبيت الأوّل. إن كان فضفاضاً، حتى لو بُنيت النواة بعناية، صار المحدِّث أضعف موضع.

مسار التحديث هو الأطول استخداماًمسار التحديث يُستخدم أطول من التثبيت الأوّل، فإن كان محيط التحديث فضفاضاً صار المحدِّث أضعف موضع في التطبيق كلّه.يُستخدم مرّةيُستخدم طويلاًالتثبيت الأوّلعمر التطبيقمسار التحديثإن كان فضفاضاً صار الأضعف

الشكل 9: مسار التحديث يُستخدم أطول من التثبيت الأوّل، وبناؤه فضفاضاً يجعله أكبر نقطة ضعف.

حول التحديث خمس نقاط تريد التفكير فيها في الحدّ الأدنى.

  • جلب ملف التحديث بافتراض HTTPS
  • التحقّق من توقيع أو هاش مادّة التحديث بعد التنزيل
  • منع استبدال عنوان مصدر التحديث بلا قيد من الشيفرة أو الإعداد
  • توقيع مكوّن التحديث نفسه أيضاً
  • تحديد التراجع أو إجراء الاستعادة عند الفشل

إن أمكن اعتماد MSIX + App Installer، يسهل تقريب آلية التحديث نحو نظام التشغيل. أمّا إن حملت محدِّثاً خاصّاً، فلزم التحقّق من أمان الاتّصال و أصالة مادّة التوزيع كليهما. HTTPS وحده يحمي «مسار الاتّصال» ولا يضمن «أن هذا الملف صادر فعلاً عنك».

أمران يُتحقَّق منهما في التحديثالمحدِّث الخاص يحتاج التحقّق من أمان الاتّصال عبر HTTPS ومن الأصالة عبر توقيع مادّة التحديث المنزَّلة أو هاشها.جلب ملف التحديث عبر HTTPSالتحقّق من التوقيع أو الهاشتطبيق ما اجتاز التحقّق فقطHTTPS يحمي مسار الاتّصال فقطالتثبّت من أنه صادر عنك

الشكل 10: الجلب عبر HTTPS لا يحسم الأصالة؛ طبّق بعد اجتياز التحقّق من التوقيع أو الهاش.

3.5. عدم وضع الأسرار في الشيفرة أو إعداد نصّ صريح

هذا موضع تقع فيه الحوادث فعلاً في العمل اليومي. بعبارات «أداة داخلية» أو «نوزّع exe فقط على أي حال»، تُوضَع سلاسل الاتّصال ومفاتيح API وبيانات اعتماد المجلد المشترك والرموز الثابتة في الشيفرة أو ملف الإعداد.

في الحدّ الأدنى تريد تجنّب هذه الأشكال.

  • مفتاح API مكتوب مباشرة في الشيفرة
  • كلمة مرور نصّ صريح في appsettings.json أو app.config
  • سلسلة اتّصال دخلت المستودع
  • تصميم يضع مفتاح فكّ التشفير والنصّ المشفَّر في الموضع نفسه
  • بيانات اعتماد ثابتة مشتركة للجميع لا لكل مستخدم

الخيارات الواقعية في تطبيق Windows تقريباً هذه الأربعة.

  • تريد حفظ بيانات اعتماد Windows في تطبيق سطح مكتب محزوم / عائلة WinUI انظر إلى Credential Locker
  • تريد حفظ سرّ مشفَّراً محليّاً في Win32 / .NET استخدم DPAPI / ProtectedData
  • جهة الاتّصال تستطيع مصادقة Windows أو المصادقة المتكاملة إن أمكن فلا تحمل كلمة مرور في التطبيق
  • يمكن إدارة السرّ في السحابة أو جهة الخادم فضّل تصميماً لا يضمّن سرّاً طويل الأجل في العميل

في C#، مجرّد استخدام DPAPI كما يلي أفضل بكثير من الحفظ بنصّ صريح. ذهاباً وإياباً بين الحفظ والقراءة يصير كالتالي.

// C# / .NET 8。ProtectedData は Windows 専用で、
// .NET では NuGet パッケージ System.Security.Cryptography.ProtectedData が必要です。
using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;

public static class SecretStore
{
    // 復号時にも同じ値が要る。null でも動くが、付けたほうが安全。
    private static readonly byte[] Entropy = [0x4b, 0x53, 0x2d, 0x76, 0x31];

    public static void Save(string path, string secretText)
    {
        byte[] plaintext = Encoding.UTF8.GetBytes(secretText);

        byte[] ciphertext = ProtectedData.Protect(
            plaintext,
            Entropy,
            DataProtectionScope.CurrentUser);

        // バイト列のままファイルへ置いてもよいが、設定ファイルへ入れるなら Base64 にする。
        File.WriteAllText(path, Convert.ToBase64String(ciphertext));

        CryptographicOperations.ZeroMemory(plaintext);
    }

    public static string Load(string path)
    {
        byte[] ciphertext = Convert.FromBase64String(File.ReadAllText(path));

        // 保存したときと同じユーザー、同じ entropy でなければ CryptographicException になる。
        byte[] plaintext = ProtectedData.Unprotect(
            ciphertext,
            Entropy,
            DataProtectionScope.CurrentUser);

        try
        {
            return Encoding.UTF8.GetString(plaintext);
        }
        finally
        {
            CryptographicOperations.ZeroMemory(plaintext);
        }
    }
}

طرف الاستدعاء يصير كالتالي.

string path = Path.Combine(
    Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
    "SampleApp",
    "token.dat");

Directory.CreateDirectory(Path.GetDirectoryName(path)!);

SecretStore.Save(path, "example-api-key");
string restored = SecretStore.Load(path);

المهم هنا ليس «شفّرنا إذن آمن»، بل حسم من يستطيع فكّ التشفير في التصميم. المعنى يتغيّر كثيراً بين CurrentUser و LocalMachine. CurrentUser لا يفكّ إلا المستخدم الذي حفظ، و LocalMachine يستطيع أيّ شخص على الجهاز نفسه فكّ التشفير. إن شغّلت كخدمة بحساب آخر، أو كان هناك تشغيل بتبديل المستخدم، فبدون حسم هذا أوّلاً تتعثّر لاحقاً عند «لا يُقرأ» أو «يُقرأ بلا قصد».

من يستطيع فكّ التشفير في DPAPIنطاق DPAPI إن كان CurrentUser لا يفكّ إلا المستخدم الذي حفظ، وإن كان LocalMachine يستطيع أيّ شخص على الجهاز نفسه فكّ التشفير، لذا يلزم حسم من يستطيع فكّ التشفير في التصميم أوّلاً.CurrentUserLocalMachineحسم من يستطيع فكّ التشفير في التصميمالمستخدم الحافظ فقطأيّ شخص على الجهاز نفسهبدون الحسم تتعثّر لاحقاً

الشكل 11: DPAPI يغيّر نطاق من يستطيع فكّ التشفير حسب اختيار النطاق، فاحسم «من يستطيع فكّ التشفير» أوّلاً.

لاحظ أن DPAPI يحمل المفتاح في ملف تعريف المستخدم، والتوثيق يصرّح بأن فكّ التشفير يفشل إن لم يكن الملف محمَّلاً (أثناء impersonation مثلاً). إن فكّرت في الاستخدام من خدمة فتثبّت من هذه النقطة أيضاً.

مفتاح DPAPI وملف تعريف المستخدمDPAPI يحمل المفتاح في ملف تعريف المستخدم، لذا يفشل فكّ التشفير إن لم يكن الملف محمَّلاً كما أثناء impersonation.الملف غير محمَّل (أثناء impersonation وغيره)مفتاح DPAPIفي ملف تعريف المستخدميفشل فكّ التشفيريلزم التثبّت عند الاستخدام من خدمة

الشكل 12: مفتاح DPAPI في ملف تعريف المستخدم، ولا يمكن فكّ التشفير إن لم يكن الملف محمَّلاً.

لاتّصال SQL Server، قد تكون مصادقة Windows المرشّح الأوّل في بيئة محلية. إن اضطررت لتضمين بيانات اعتماد في سلسلة الاتّصال، فأبقى على الأقل Persist Security Info=False، ولا تتركها في ملف إعداد نصّ صريح.

3.6. الاتّصال بافتراض HTTPS، ولا تقتل التحقّق من الشهادات

ثغرة وُضعت بنيّة التطوير فقط تبقى في الإنتاج كما هي. حوادث محيط الاتّصال تقريباً بهذا النمط.

ما يبقى بسهولة في مادّة الشحن شيفرة أو إعداد من هذا النوع.

  • ServicePointManager.ServerCertificateValidationCallback += ... => true
  • HttpClientHandler.DangerousAcceptAnyServerCertificateValidator
  • الشحن مع تعطيل التحقّق من إلغاء الشهادة
  • إبقاء شيفرة تفترض شهادة موقَّعة ذاتياً للتطوير في الإنتاج

الاتجاه الأدنى بسيط.

  • اتّصال الإنتاج HTTPS
  • عدم تخطّي التحقّق من الشهادات دائماً
  • إن لزم تخفيف استثنائي للتحقّق فـ قيّد المضيف المستهدف والشهادة
  • استبعد شيفرة التجاوز التطويرية حتماً بشرط بناء أو إعداد
  • في .NET انتبه أيضاً إلى التحقّق من الإلغاء

المثال السيّئ تقريباً كالتالي.

ServicePointManager.ServerCertificateValidationCallback +=
    (_, _, _, _) => true;

يبدو مريحاً، غير أن الحركة تقترب من «هذا الاتّصال HTTPS يمرّ لأيّ طرف». إن نزعت التحقّق من الشهادات، حتى مع HTTPS يصير المحتوى مفرَّغاً جدّاً.

الكتابة تتغيّر حسب جيل .NET المفترض

وضع إعداد عام على ServicePointManager كتابة عهد .NET Framework. في الشيفرة الجديدة أوضح تلقّي HttpClient من IHttpClientFactory، وإن لزم إعداد حول TLS فاحمله في جهة SocketsHttpHandler أو HttpClientHandler.

غير أن ترك الأمر بعبارة «واجهة قديمة إذن لم تعد تؤثّر» خطر. توثيق Microsoft يذكر أن ServicePointManager.ServerCertificateValidationCallback يُربَط منذ .NET 9 بـ RemoteCertificateValidationCallback في SocketsHttpHandler.SslOptions. أي أن سطر => true واحد في موضع ما قد يمرّر حتى اتّصال HttpClient.

مسار تأثير الاستدعاء الراجع القديم على الاتّصال الحاليServerCertificateValidationCallback في ServicePointManager يُربَط منذ .NET 9 باستدعاء التحقّق في SocketsHttpHandler، لذا قد يمرّر سطر true واحد حتى اتّصال HttpClient..NET 9 فما بعد يُربَطاستدعاء التحقّق في ServicePointManagerالتحقّق في جهة SocketsHttpHandlerيؤثّر أيضاً في اتّصال HttpClientسطر true واحد قد يفرّغ الاتّصال كلّه

الشكل 13: تخطّي التحقّق الموضوع على واجهة قديمة قد يمرّ عبر الربط حتى اتّصال HttpClient الحالي.

إن أردت تخفيف التحقّق استثناءً، فلا تستخدم إعداداً عامّاً يؤثّر في العملية كلّها، بل شكلاً مغلقاً على ذلك المعالج فقط.

// C# / .NET 8. مثال يستثني مضيفاً وشهادة معيّنين فقط.
// حتى إن رخّصت للتطوير، إن لم تحدّد الهدف فهو كقتل التحقّق عالمياً.
using System;
using System.Linq;
using System.Net.Http;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;

// بصمة إبهام الشهادة المستهدفة. يجوز قراءتها من الإعداد.
const string ExpectedThumbprint = "2B0C4E6A8D1F3B5D7F9A1C3E5A7C9E1B3D5F7A91";

var handler = new HttpClientHandler
{
    CheckCertificateRevocationList = true,   // انظر في الإلغاء. الافتراضي false
    ServerCertificateCustomValidationCallback = (request, certificate, chain, errors) =>
    {
        if (errors == SslPolicyErrors.None)
        {
            return true;
        }

        // ما يُقبل نقطة واحدة فقط: «هذه المحطة لا تثق بـ CA الداخلي».
        // عدم وصول الشهادة أو عدم تطابق اسم المضيف لا يُقبلان
        if (errors != SslPolicyErrors.RemoteCertificateChainErrors)
        {
            return false;
        }

        // ثبِّت الطرف والشهادة
        if (request.RequestUri?.Host != "device.internal.example"
            || certificate is null
            || !string.Equals(certificate.Thumbprint, ExpectedThumbprint,
                              StringComparison.OrdinalIgnoreCase))
        {
            return false;
        }

        // حتى الشهادة المُثبَّتة واحدة لا يُقبل انتهاء أجلها ولا إلغاؤها.
        // لحظة القبول يصير مساراً يستمر في استخدام «شهادة أُلغيت لأن المفتاح تسرّب»
        return chain is not null
            && chain.ChainStatus.All(s =>
                   s.Status is X509ChainStatusFlags.NoError
                            or X509ChainStatusFlags.UntrustedRoot
                            or X509ChainStatusFlags.PartialChain);
    },
};

using var client = new HttpClient(handler);

ExpectedThumbprint تُعطى كقيمة ثابتة أو من إعداد، وهي بصمة الشهادة المستهدفة.

المهم هنا ألّا تتجاهل errors و chain.ChainStatus. إن أعدت true لأن البصمة تطابقت، مرّ الأمر حتى إن انتهت صلاحية تلك الشهادة، أو حتى بعد تسريب المفتاح وإلغائها. التثبيت يعني «نثق بهذه الشهادة الواحدة فقط»، لا «نثق بهذه الواحدة مهما حدث». ما تسمح به الشيفرة أعلاه هو UntrustedRoot و PartialChain فقط (أي أن مرجع التصديق الداخلي غير مثبَّت على هذا الجهاز)، و NotTimeValid (انتهاء الأجل) و Revoked (الإلغاء) يُرفضان كما هما.

لرؤية الإلغاء يلزم CheckCertificateRevocationList = true (الافتراضي false ولا يُتحقَّق من الإلغاء). في المقابل، إن كان مرجع التصديق الداخلي لا ينشر CRL ولا OCSP، يُرفَض بـ RevocationStatusUnknown. وهذا السلوك الصحيح. إن تعذّر تجهيز وسيلة التحقّق من الإلغاء فاملأ الفجوة إمّا بـ تقصير مدّة صلاحية الشهادة أو بـ صنع مسار لإعادة توزيع القيمة المُثبَّتة مسبقاً. أخطر حالة هي «تثبيت شهادة طويلة الأجل دون القدرة على إلغائها».

تدفّق الحكم عند التثبيتبلا أخطاء يُمرَّر، وما عدا خطأ السلسلة يُرفَض، ويُثبَّت اسم المضيف والبصمة، وفي حالة السلسلة أيضاً يُرفَض انتهاء الأجل والإلغاء.Noneغير خطأ السلسلةخطأ السلسلة فقطعدم تطابقتطابقانتهاء أجل أو إلغاء وغيرهماحالة عدم إدخال مرجع التصديق الداخلي فقطفحص errorsتمريررفضمطابقة اسم المضيف والبصمةفحص حالة السلسلة

الشكل 14: حتّى مع التثبيت لا تتجاهل، فتدفّق الحكم يرفض انتهاء الأجل والإلغاء كما هما.

3.7. معاملة الإدخال الخارجي كلّه كـ «إدخال غير موثوق»

تطبيق Windows ليس تطبيق ويب، فيميل التحقّق من الإدخال إلى التساهل. غير أن مداخل الإدخال الخارجي عمليّاً أكثر ممّا يُظَنّ.

  • مسار ملف
  • CSV / Excel / JSON / XML
  • وسائط سطر الأوامر
  • named pipe / socket / COM / RPC / gRPC
  • نصّ يُمرَّر إلى قاعدة البيانات
  • قيم السجلّ
  • الحافظة
  • URL / deep link
  • بيانات تعود من جهاز خارجي أو SDK

ما لا تريد إسقاطه خصوصاً في الحدّ الأدنى ثلاثة.

  1. اجعل SQL مُعلَّم المعاملات حتماً لا تركّب SQL بربط سلاسل.
  2. طبّع مسار الملف ثم استخدمه لا تستخدم مساراً يحدّده المستخدم كما هو للحذف أو الكتابة فوقه أو فكّه.
  3. ضع حدّ حجم وفحص صيغة عند قراءة ملف خارجي «فُتح إذن آمن» ليس صحيحاً.

في مثال SQL، تجنّب هذا.

var sql = "SELECT * FROM Users WHERE Name = '" + userName + "'";

حتّى في الحدّ الأدنى أزِح نحو هذا.

using System.Data;
using Microsoft.Data.SqlClient;

using var cmd = connection.CreateCommand();
cmd.CommandText = "SELECT * FROM Users WHERE Name = @name";
cmd.Parameters.Add("@name", SqlDbType.NVarChar, 256).Value = userName;

«أداة داخلية إذن الإدخال موثوق» مقدّمة خطرة جدّاً. عمليّاً يدخل CSV تالف، واسم ملف غير متوقَّع، وبيانات قاعدة قديمة، وخطأ إدخال يدوي من المشغّل، و JSON ناقص كتبته أداة أخرى، بشكل عادي.

حتّى الأداة الداخلية يصلها إدخال تالفحتّى الأداة الداخلية يصلها بشكل عادي CSV تالف واسم ملف غير متوقَّع وبيانات قاعدة قديمة وخطأ إدخال يدوي و JSON ناقص، لذا يُعامَل الإدخال الخارجي كلّه كإدخال غير موثوق.CSV تالفإدخال إلى التطبيقاسم ملف غير متوقَّعخطأ إدخال يدوي وبيانات قديمةالتحقّق كإدخال غير موثوق كلّه

الشكل 15: حتّى الأداة الداخلية يصلها إدخال تالف بشكل عادي، فتحقّق عند كل مدخل ثم استخدم.

3.8. لا تترك مصدر تحميل DLL غامضاً

هذا فخّ على طابع Windows. إن حمّلت DLL بالاسم وحده مثل LoadLibrary("foo.dll")، فقد تلتقط DLL من موضع غير مقصود حسب ترتيب البحث.

ما يُفعَل محدَّد.

  • إن أمكن فحدّد المسار المطلق لـ DLL
  • اضبط SetDefaultDllDirectories(LOAD_LIBRARY_SEARCH_DEFAULT_DIRS) في مرحلة مبكّرة
  • أضف هدف البحث صراحة بـ AddDllDirectory
  • تجنّب تصميماً يمرّر نتيجة SearchPath كما هي إلى LoadLibrary
  • لا تعتمد كلّ الاعتماد على safe DLL search mode

مثلاً في شيفرة أصلية، إدخال التالي في مرحلة مبكّرة من تهيئة العملية خيار قوي.

SetDefaultDllDirectories(LOAD_LIBRARY_SEARCH_DEFAULT_DIRS);

ثم سجّل الأدلّة الإضافية اللازمة فقط بـ AddDllDirectory.

هذا الموضع يُترَك بسهولة لأنه «يعمل عادة»، غير أنه ينكسر بهدوء إن تغيّر دليل العمل في جهة التوزيع، أو دخلت DLL منتج آخر إلى PATH. يؤثّر لا في الأمان فقط، بل أيضاً كوقاية من الأعطال.

تثبيت مصدر تحميل DLLالتحميل بالاسم وحده قد يلتقط DLL من موضع غير مقصود حسب ترتيب البحث؛ فاضبط SetDefaultDllDirectories مبكّراً، وأضف هدف البحث صراحة بـ AddDllDirectory، وإن أمكن فحدّد مساراً مطلقاً.التحميل بالاسم وحدهالتقاط DLL غير مقصودة حسب ترتيب البحثSetDefaultDllDirectories مبكّراًإضافة صريحة بـ AddDllDirectoryمسار مطلق إن أمكنمصدر التحميل لا يبقى غامضاً

الشكل 16: أوقف التحميل بالاسم وحده، وصرّح بهدف البحث وثبّت مصدر التحميل.

3.9. لا تخرج أسراراً في السجلات والاستثناءات

زيادة السجلات لأجل التحقيق في الأعطال مهمّة. غير أن السجلات تصير أيضاً بسهولة مقبرة للأسرار.

ما تريد مراجعته في الحدّ الأدنى حول السجلات:

  • لا تخرج كلمات المرور أو Bearer token أو مفاتيح API إلى السجلّ
  • لا تخرج سلسلة الاتّصال كاملة
  • أخفِ البيانات الشخصية ومتن بيانات الأعمال
  • افصل تفاصيل الاستثناء بين شاشة المستخدم والسجلّ الداخلي
  • لا تفعّل سجلات PII الخاصّة بالتصحيح في الإنتاج
  • راجع صلاحيات موضع حفظ dump و trace

في .NET الحديث صار الترتيب بافتراض الإخفاء (redaction) أسهل أيضاً. على الأقل تريد إيقاف «حوّل كل شيء إلى نصّ وسجّله كما هو».

إخفاقات شائعة:

  • حفظ متن طلب / استجابة HTTP كاملاً
  • إخراج الرمز أو الترويسة كلّها عند فشل المصادقة
  • عرض رسالة الاستثناء كما هي في MessageBox
  • تضمين سجلات سرّيّة كلّها في ZIP للصيانة

عرض الخطأ مثلاً يُفصَل كالتالي.

  • للمستخدم: «فشل الاتّصال بالخادم. راجع إعداد الشبكة و URL.»
  • السجلّ الداخلي: المضيف الذي فشل، نوع خطأ TLS، معرّف الارتباط، stack trace، عدد إعادة المحاولة

هذا الفصل وحده يحسّن كثيراً توازن منع التسرّب وقابلية التحقيق.

فصل عرض الخطأعند حدوث خطأ يُخرَج للمستخدم توجيه موجز فقط، ويُبقى في السجلّ الداخلي معلومات التحقيق مثل المضيف الذي فشل ونوع الخطأ ومعرّف الارتباط و stack trace.حدوث خطأللمستخدم: توجيه موجز فقطالسجلّ الداخلي: مضيف ونوع ومعرّف ارتباط وغيرهامنع التسرّب مع الإبقاء على قابلية التحقيق

الشكل 17: فصل عرض المستخدم عن السجلّ الداخلي وحده يحسّن توازن التسرّب وقابلية التحقيق.

3.10. لا تترك مكتبات التبعية وأدوات التطوير بلا متابعة

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

البنود نفسها ليست كثيرة.

  • إبقاء .NET SDK / runtime ضمن إصدار مدعوم
  • مراجعة تحديثات تبعيات NuGet / OSS دوريّاً
  • في C++ إدارة إصدارات إعادة توزيع وقت التشغيل و DLL الخارجية
  • إدخال مراجعة معلومات الثغرات في التحقّق قبل الإصدار
  • تجهيز اختبار دخان حتى لا ينكسر الأمر بتحديث التبعية

هنا «سنفعله مجمَّعاً لاحقاً» هو الأخطر. إن تُرك نصف سنة أو سنة، كبر فرق التحديث أكثر من اللازم، وصارت معالجة الأمان نفسها عملاً ثقيلاً.

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

الشكل 18: كلّما تُرك تحديث التبعيات تضخّم الفرق، وصارت المعالجة نفسها عملاً ثقيلاً.

3.11. كيف نتحقّق من كل بند؟

قائمة التحقّق لا تعمل إلا مع طريقة التحقّق. لبنود 3.2 إلى 3.10 نرتّب ما يمكن طرقه فعلاً قبل الإصدار.

ما نريد التحقّق منه طريقة التحقّق
هل يُطلب رفع؟ انظر قيمة requestedExecutionLevel في بيان التطبيق. في المصدر app.manifest، وفي مادّة التوزيع Sigcheck من Sysinternals أو محرّر الموارد
التوقيع والطابع الزمني نفّذ في PowerShell Get-AuthenticodeSignature .\app.exe، وانظر هل Status هو Valid وهل دخل TimeStamperCertificate. انظر أيضاً DLL المضمَّنة والمحدِّث واحداً واحداً
هل قُتل التحقّق من الشهادات؟ ابحث في المصدر كلّه عن ServerCertificateValidationCallback و DangerousAcceptAnyServerCertificateValidator و ServerCertificateCustomValidationCallback و CheckCertificateRevocationList
كتابة الأسرار مباشرة ابحث عن Password= و ApiKey و Secret و Token و ConnectionString. لا المصدر الحالي فقط، بل تاريخ المستودع أيضاً
تركيب SQL ابحث عن ربط سلاسل يشمل "SELECT و "INSERT و + ، وتأكّد أنه يمرّ عبر Parameters.Add
مصدر تحميل DLL في Process Monitor ضيّق على العملية المستهدفة، وضَع مرشّحي Path ends with .dll و Result is NAME NOT FOUND. يظهر أين وبأي ترتيب بُحث، فتتحقّق من عدم النظر إلى مجلد غير مقصود
ثغرات معروفة في التبعيات نفّذ dotnet list package --vulnerable --include-transitive
هل خرجت أسرار في السجلات؟ شغّل مرّة ثم ابحث في السجلات الخارجة عن Bearer و Password و Authorization

بحث الشيفرة يجوز بـ rg (ripgrep) أو بحث Visual Studio. للطرق مجمَّعاً هذا الشكل.

Get-ChildItem -Recurse -Include *.cs,*.vb,*.cpp,*.h,*.config,*.json |
    Select-String -Pattern 'ServerCertificateValidationCallback|DangerousAcceptAnyServerCertificateValidator|Password=|ApiKey' |
    Select-Object Path, LineNumber, Line

المهم إبقاء التحقّق نفسه في السجلّ. إن أبقيت حتى «بحثنا» و«كانت النتيجة صفر»، اكتفيت في الإصدار التالي بالنظر إلى الفرق فقط.

أثر إبقاء التحقّق في السجلّتحقّق ما قبل الإصدار حتى إن كانت النتيجة صفراً إن أُبقي في السجلّ اكتفيت في الإصدار التالي بالنظر إلى الفرق فقط.تنفيذ التحقّق قبل الإصدارتسجيل حتى بحثنا وكانت النتيجة صفراًالإصدار التالي يكفي فيه النظر إلى الفرق

الشكل 19: إبقاء واقعة «تحقّقنا» حتى في السجلّ يكفي بعده بالنظر إلى فرق التحقّق فقط.

4. قائمة التحقّق قبل الإصدار

نجعلها شكلاً يُستخدم كما هو كقالب مراجعة أو حكم شحن. لتسهيل التحقّق بالجدول نرتّب البنود التي تريد النظر إليها في الحدّ الأدنى قبل الإصدار حسب الفئة.

4.1. الصلاحيات وطريقة التشغيل

بند التحقّق التحقّق ملاحظة
التشغيل العادي يعمل بـ asInvoker □  
المعالجة التي تحتاج امتيازات مدير مفصولة إلى EXE / خدمة وغيرها □  
عند استخدام خدمة، حساب التشغيل ليس أقوى من اللازم □  
فصل المسؤوليات بين ما تحت %ProgramFiles% وما تحت بيانات المستخدم □  

4.2. التوزيع والتوقيع

بند التحقّق التحقّق ملاحظة
توقيع EXE / DLL / MSI / MSIX / المحدِّث □  
إرفاق طابع زمني للتوقيع □  
إدخال أجل الشهادة وإجراء التجديد في مسار الإصدار □  
تحديد طريقة التحقّق من هاش مادّة التوزيع أو كشف العبث □  

4.3. التحديث

بند التحقّق التحقّق ملاحظة
جلب التحديث عبر HTTPS □  
التحقّق من التوقيع أو الهاش بعد التنزيل □  
تصميم يصعّب استبدال عنوان مصدر التحديث جزافاً □  
وجود سياسة تراجع أو إعادة محاولة عند فشل التحديث □  

4.4. الأسرار

بند التحقّق التحقّق ملاحظة
كلمات المرور ومفاتيح API وسلاسل الاتّصال غير مكتوبة مباشرة في الشيفرة □  
لا سرّ في ملف إعداد نصّ صريح □  
السرّ الذي يلزم حفظه محليّاً محمي بـ DPAPI / Credential Locker وغيرهما □  
الإزاح حيث أمكن نحو مصادقة Windows أو بيانات اعتماد المستخدم □  

4.5. الاتّصال

بند التحقّق التحقّق ملاحظة
اتّصال الإنتاج يستخدم HTTPS □  
DangerousAcceptAnyServerCertificateValidator أو => true غير باقٍ في مادّة الشحن □  
الوعي بالتحقّق من الإلغاء والتحقّق من اسم المضيف □  
شيفرة أو إعداد يفترض شهادة تطوير غير مختلط في الإنتاج □  

4.6. الإدخال والوصول إلى البيانات

بند التحقّق التحقّق ملاحظة
SQL معلَّم المعاملات □  
إدخال سطر الأوامر والملفات و IPC و URI وغيرها له حدّ وفحص صيغة □  
عمليات المسار مطبَّعة وتمنع الخروج عن الجذر □  
رسالة الاستثناء لا تُعرَض كما هي على الشاشة □  

4.7. DLL وبيئة التشغيل

بند التحقّق التحقّق ملاحظة
مصدر تحميل DLL مصرَّح به □  
ترتيب البحث مضبوط بـ SetDefaultDllDirectories / AddDllDirectory وغيرهما □  
لا تحميل DLL بإسناد إلى الدليل الحالي أو PATH □  
مجموعة الملفات اللازمة للتحميل الديناميكي في جهة التوزيع معروفة □  

4.8. السجلات والتشغيل

بند التحقّق التحقّق ملاحظة
الرموز وكلمات المرور و PII لا تخرج إلى السجلّ □  
فصل السجلّ الداخلي عن رسالة المستخدم □  
مراجعة صلاحيات موضع حفظ dump / trace / log □  
مراجعة حالة تحديث SDK ومكتبات التبعية □  

5. رفض شائع

ما يُشاهَد كثيراً في العمل اليومي تقريباً هذه الاعتقادات.

5.1. «أداة داخلية إذن بخير»

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

5.2. «HTTPS إذن آمن»

HTTPS مهمّ، غير أن تعطيل التحقّق من الشهادات يفرّغ المعنى كثيراً. وفي توزيع التحديث يلزم، فضلاً عن HTTPS، التحقّق من أصالة مادّة التوزيع أيضاً.

5.3. «شفّرنا إذن آمن»

إن لم يُرتَّب موضع مفتاح فكّ التشفير وصلاحية الفكّ وحدّ المستخدم وحدّ الجهاز، فالتشفير وحده لا يكفي. خصوصاً استخدام قيمة محمية بـ LocalMachine بظنّ أنها «سرّ لكل مستخدم» يربك لاحقاً.

5.4. «زيادة السجلات تمكّن التحقيق»

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

5.5. «التشغيل كمدير يحلّ الأمر»

أوّلاً مريح، غير أنه لاحقاً يتعسّر غالباً عند UAC والتوزيع والدعم وحدود الصلاحيات وتحميل DLL وموضع حفظ الملفات. أقلّ صلاحية أثبت على المدى الطويل.

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

الشكل 20: راحة الاستخدام المعتاد كمدير أوّلية فقط، وعلى المدى الطويل أقلّ صلاحية أثبت.

6. أولوية تقريبية

إن ثقل فعل الكلّ دفعة واحدة، فالأولوية تقريباً كالتالي.

معيار الترتيب حاصل ضرب حجم الضرر عند وقوع الحادث و انخفاض تكلفة الإصلاح. الفصل 3 مرتَّب بمسار التصميم «صلاحيات ← توزيع ← تنفيذ ← تشغيل»، أمّا هنا فالترتيب «من الأخطر»، لذا لا يتطابق مع ترتيب الفصول. أرفق الفصل المقابل.

  1. مراجعة امتيازات المدير (3.2) أوقف أوّلاً الاستخدام المعتاد لـ requireAdministrator. نطاق الضرر يتغيّر درجة، وغالباً يكفي كتغيير تصميم صغير.
  2. التوقيع والطابع الزمني (3.3) رتّب موثوقية مادّة التوزيع. يكفي إدخاله في الخطوات، وإدخاله لاحقاً يتطلّب إعادة توزيع.
  3. إخراج الأسرار (3.5) أخرج السرّ من الشيفرة وإعداد النصّ الصريح. الضرر عند التسرّب كبير، وبعد التسرّب لا يُستعاد.
  4. تصحيح HTTPS + التحقّق من الشهادات (3.6) احذف عائلة => true من مادّة الشحن. غالباً يُصلَح بالحذف وحده، وتركه يجعل الاتّصال كلّه غير قابل للثقة.
  5. مراجعة إدخال SQL / الملفات / IPC (3.7) قلّل ربط السلاسل والإدخال بلا تحقّق. العدد كثير، غير أنه يُصلَح موضعاً موضعاً.
  6. تثبيت تحميل DLL (3.8) أوقف التحميل بالاسم وحده والإسناد إلى PATH. عمل يصلح جزءاً من معالجة الإقلاع، ويفيد أيضاً كوقاية من الأعطال.
  7. إخفاء السجلات (3.9) حتى لا تصير السجلات كارثة ثانوية عند الحادث. مواضع الخرج كثيرة فيستغرق وقتاً.
  8. تثبيت تحديث التبعيات كعادة (3.10) اجعله مساراً يُراجَع عند كل إصدار. لا ينتهي بمرّة، فالعمل حتى يصير آلية.

مسار التحديث (3.4) غير داخل في هذا الترتيب لأن بعض التطبيقات لا تحمل تحديثاً تلقائيّاً. إن حملته فانظر إليه بالأولوية نفسها كالرقم 2 التوقيع. مكوّن التحديث أضعف من النواة ومع ذلك في موضع يستطيع إعادة كتابتها.

طريقة وضع الأولويةرُتِّب من الأخطر بحاصل ضرب حجم الضرر عند الحادث وانخفاض تكلفة الإصلاح، وفي تطبيق يحمل تحديثاً تلقائيّاً يُنظَر إلى مسار التحديث بأولوية التوقيع نفسها.حجم الضررحسم الترتيب بالحاصلانخفاض تكلفة الإصلاحالسدّ من الأخطرإن وُجد تحديث تلقائي فمسار التحديث بأولوية التوقيع نفسها

الشكل 21: الأولوية تُحسَم بحاصل حجم الضرر وتكلفة الإصلاح، وتُسَدّ الثقوب من الأخطر.

بهذا الترتيب يسهل التقدّم بمعنى «سدّ الثقب الواضح الخطر أوّلاً».

7. الخلاصة

أمان تطوير تطبيقات Windows، حتى قبل إدخال منتج خاص أو آلية ضخمة، يتغيّر كثيراً بترتيب سبع نقاط فقط: الصلاحيات، والتوقيع، والأسرار، والاتّصال، والإدخال، و DLL، والسجلات.

الخطّ الأدنى جملة جملة يصير كالتالي.

  • لا تشغّل التطبيق كلّه بامتيازات مدير
  • وقّع مادّة التوزيع ومادّة التحديث وأرفق طابعاً زمنيّاً
  • لا تضع الأسرار في الشيفرة أو إعداد نصّ صريح
  • حتى مع HTTPS لا تقتل التحقّق من الشهادات
  • لا تثق بالإدخال الخارجي مثل SQL والملفات و IPC
  • لا تترك مصدر تحميل DLL غامضاً
  • لا تخرج أسراراً إلى السجلات
  • لا تترك مكتبات التبعية بلا متابعة

حديث الأمان واسع، غير أنك لست مضطرّاً لفعل الكلّ من البداية. فقط عدم شحن سلوك افتراضي خطر كما هو كحدّ أدنى يستحق الترتيب في مرحلة مبكّرة جدّاً.

8. روابط مرجعية

أحدث المقالات التي تشترك في نفس الوسوم. عمّق فهمك بمواضيع مرتبطة.

ترتبط هذه المقالة بشكل طبيعي بصفحات الخدمات التالية.

تطوير تطبيقات ويندوز

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

الأسئلة الشائعة

أسئلة شائعة حول موضوع هذه المقالة.

ما الذي ينبغي النظر إليه أوّلاً في أمان تطبيق Windows؟
أربع نقاط: عدم طلب امتيازات مدير غير لازمة، وتوقيع الشيفرة، وعدم حفظ الأسرار بنصّ صريح، وعدم تعطيل التحقّق من الشهادات. الأمان الأدنى ليس إضافة ميزة خاصّة بقدر ما هو عدم إبقاء سلوك افتراضي خطر أو تنفيذ فضفاض. تخطّي التحقّق من الشهادات دائماً، وسلاسل الاتّصال بنصّ صريح، وتحميل DLL بإسناد إلى الدليل الحالي، وتنفيذ SQL بربط سلاسل، بنود ينبغي تجنّبها حتى على الخطّ الأدنى.
هل يُمنَع تشغيل التطبيق كلّه بامتيازات مدير؟
ينبغي تجنّبه. إن شغّلت التطبيق كلّه بامتيازات مدير، نُفِّذت الأخطاء واستبدال DLL وسوء قراءة ملف الإعداد وعيوب الإدخال الخارجي بالصلاحيات القوية كما هي. تطبيق واجهة المستخدم العادي أساسه asInvoker، وتُفصَل المعالجة التي تحتاج امتيازات مدير إلى عملية أو خدمة منفصلة، ويُجرى الرفع في اللحظة اللازمة فقط. هذا هو الاتجاه الأساسي.
أين ينبغي حفظ مفاتيح API أو سلاسل الاتّصال؟
ينبغي أوّلاً الخروج من وضعها بنصّ صريح في الشيفرة المصدرية أو ملفات إعداد مثل appsettings.json. أسرار الحفظ تُوزَّع حسب الاستخدام بين DPAPI / ProtectedData و Credential Locker. وإذا بقيت الرموز أو كلمات المرور أو سلاسل الاتّصال أو البيانات الشخصية في السجلات كما هي، صارت السجلات نفسها بطلة الحادث، لذا يلزم الإخفاء.
هل يلزم توقيع الشيفرة حتى لتطبيق يُوزَّع داخل المؤسسة؟
الأفضل اعتباره مقدّمة. في تطبيقات Windows تصير مادّة التوزيع نفسها (EXE / DLL / MSI / MSIX / مكوّن التحديث التلقائي) سطح هجوم. مع توقيع الشيفرة + طابع زمني تحصل على كشف العبث، وثقة المستخدم، وسهولة الشرح التشغيلي. وآلية التحديث أيضاً ينبغي تثبيت مصدر التحديث وجعل العبث قابلاً للكشف عبر HTTPS والتحقّق من التوقيع.

الملف الشخصي للمؤلف

صفحة الملف الشخصي لمؤلف المقالة.

غو كومورا

مؤسّس شركة كومورا سوفت ذ.م.م.

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

العودة إلى المدونة