تجيب الأذونات في لينكس عن سؤال «من يحق له قراءة هذا الملف». أما AppArmor فيجيب عن سؤال آخر: «ما الذي يُسمح لهذا البرنامج بفعله أصلًا». ويظهر الفرق أثناء اختراق. فالـ web shell يعمل بحساب مستخدم خادم الويب ويرث كل حقوقه — وهذا وصول للقراءة إلى نصف النظام تقريبًا. أما ملف AppArmor الشخصي فيحصر العملية في قائمة ما تحتاجه لعملها، وتنتهي محاولة قراءة /etc/shadow أو تشغيل /bin/bash بالرفض بصرف النظر عن أذونات المستخدم.

ما المفعّل بالفعل

sudo aa-status

يجيب المخرج عن ثلاثة أسئلة: كم ملفًا شخصيًا محمَّل، وكم منها في وضع enforce وكم في complain، وأي العمليات تعمل بلا أي ملف شخصي. وعلى Ubuntu نموذجي ستجد بضع عشرات من الملفات الشخصية، لكن جميعها تقريبًا لبرامج مساعدة مثل man وtcpdump. أما الخدمات الأساسية — nginx و Apache و PHP-FPM — فغائبة عادة عن قائمة المحصورة.

وثلاثة أوضاع يستحق التمييز بينها:

  • enforce — تُطبَّق القواعد ويُرفض كل زائد؛
  • complain — تُسجَّل المخالفات في السجل فقط ولا يُحجب شيء. وهو وضع الضبط؛
  • unconfined — لا يوجد ملف شخصي، والبرنامج يعمل بلا قيود.

وأنفع جزء في مخرج aa-status هو الأخير: العمليات التي تستمع إلى الشبكة ولا يحصرها شيء. ومن هذه القائمة يُبدأ.

الأدوات

sudo apt install apparmor-utils

بدون هذه الحزمة لا توجد الأوامر aa-complain وaa-enforce وaa-logprof في النظام، مع أن AppArmor نفسه يعمل.

كيف تفعّل ملفًا شخصيًا دون إيقاف الخدمة

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

التسلسل الصحيح:

sudo aa-complain /etc/apparmor.d/usr.sbin.nginx

أسبوع من العمل في هذا الوضع مع تغطية كل سيناريو غير معتاد: أخذ نسخة احتياطية، وتحديث، ورفع ملفات كبيرة. ثم راجع ما تراكم:

sudo aa-logprof

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

وبعد ذلك فقط:

sudo aa-enforce /etc/apparmor.d/usr.sbin.nginx

أين تُرى حالات الرفض

تنتهي كل المخالفات إلى سجل النواة:

sudo journalctl -k | grep -i apparmor
sudo grep 'apparmor="DENIED"' /var/log/audit/audit.log

ويوجد الملف الثاني إن كان auditd مثبتًا — ومعه تكون السجلات أكثر تفصيلًا بوضوح. ويُظهر سجل الرفض اسم الملف الشخصي والعملية المطلوبة والمسار الذي جرى الوصول إليه؛ وهذا يكفي لتقرّر هل تصلح الملف الشخصي أم تفرح بأنه اشتغل.

وثمة عَرَض يستحق الحفظ: تتصرف الخدمة بغرابة — لا تقرأ إعدادًا، ولا تكتب في دليل، ولا تفتح مقبسًا — بينما تُظهر سجلاتها هي خطأ «permission denied» بأذونات صحيحة بوضوح. هذا هو AppArmor في الغالب الأعم، وأول ما تفعله هو النظر في سجل النواة.

إجراء عملي لا نظري

ملف شخصي لـ PHP-FPM أو nginx يؤتي ثماره بشكل محدد. فمع عملية محصورة، لا يستطيع web shell وصل إلى الموقع أن يقرأ ملفات النظام، ولا أن يشغّل صدفة، ولا أن يكتب أي شيء خارج الأدلة المسموح بها. ويبقى الموقع المخترق موقعًا مخترقًا بدل أن يتحوّل إلى وصول للآلة كلها — وهذا الانتقال بالذات هو ما يشكّل الجزء الأكبر من الضرر.

وترتيب معقول للتبنّي: أولًا ملف شخصي لما يطلّ على الإنترنت (خادم الويب و PHP-FPM)، ثم لقواعد البيانات، ثم حسب الحاجة. ولا داعي لتفعيل كل شيء دفعة واحدة، ولا توجد مجموعة جاهزة شاملة: فالملف الشخصي يعتمد على مكان ملفاتك.

ما يجب فحصه بانتظام

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