مدونة FireAI للأمان

بقلم FireAI Security & Research Team · نُشر في

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

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

يأتي كل جهاز Mac مزوَّدًا بشيئين يسميهما الناس «جدار الحماية». الأول هو جدار حماية التطبيقات (Application Firewall) في إعدادات النظام، وهو مفتاح لكل تطبيق للاتصالات الواردة. أما الثاني، الأكثر هدوءًا، فهو pf، مرشِّح الحزم من BSD الذي ورثه macOS من سلالة FreeBSD/OpenBSD والذي تستخدمه Apple نفسها خلف الكواليس لمشاركة الإنترنت وVPN وNAT. يمكن للمستخدمين المتقدمين والمسؤولين التحدث معه مباشرة عبر pfctl، وتعرض أدلة كثيرة مقتطف pf.conf وتكتفي بذلك. ما لا تشرحه تلك الأدلة غالبًا هو أين يتوقف pf عن أن يكون مفيدًا للشيء الذي يريده معظم الناس فعليًا: مراقبة والتحكم في ما ترسله تطبيقاتهم الخاصة إلى الخارج. هذا تمرين عملي لا محاضرة — سنفعّل pf، ونكتب قاعدة، ونقرأ الحالة التي يحتفظ بها، ثم ننظر بالضبط في سبب كون تلك الحالة الشكل الخاطئ لجدار حماية خاص بالتطبيقات.

ما هو pf فعليًا

pf مرشِّح حزم على مستوى النواة: يفحص الحزم أثناء عبورها واجهات الشبكة ويقرر، قاعدة تلو الأخرى، ما إذا كان سيمررها أو يحظرها. ليس لديه أي مفهوم لـ«التطبيقات» — يعمل بحتًا على رؤوس الحزم: عنوان المصدر والوجهة، والمنفذ، والبروتوكول، والواجهة، والاتجاه. هذا ليس قصورًا نسي أحدهم إصلاحه؛ إنه التصميم نفسه. بُني pf لتصفية الحركة على طبقة الشبكة، الطبقة نفسها التي تعمل عليها أجهزة التوجيه والبوابات، وهو بارع جدًا في تلك المهمة.

تتحدث معه عبر pfctl، أداة التحكم. دليل استخدامها صريح بشأن الفصل بين ما يفعله: فهو يحمّل مجموعات قواعد من ملف إعداد، ويُبلغ عن الحالة التي تحتفظ بها النواة. خياران هما الأهم لتفعيل المرشِّح وتعطيله، بحسب صياغة دليل الاستخدام نفسه: -e («تفعيل مرشِّح الحزم») و-d («تعطيل مرشِّح الحزم»). لا شيء آخر في pf يُفعَّل أو يُعطَّل بمفرده — تتحرك مجموعة القواعد بأكملها معًا.

تفعيله وقراءة حالته

تمرين سريع، على جهاز Mac ترتاح فيه لاستخدام sudo. أولًا، تحقق مما إذا كان المرشِّح مفعّلًا بالفعل واطّلع على عداداته:

الطرفية — حالة pf وعداداته
sudo pfctl -s info
# example output, trimmed — the real thing includes per-rule and per-source-tracking stats with -v
Status: Enabled for 0 days 02:14:07		Debug: err
State Table                          Total             Rate
  current entries                       42
  searches                           88213             9.7/s
  inserts                              611             0.1/s
  removals                             569             0.1/s

ثم اسرد القواعد التي تحتفظ بها النواة حاليًا. يفعل pfctl -s rules هذا بالضبط؛ ويشير دليل الاستخدام إلى أنه مع -v يطبع أيضًا عدد مرات تقييم كل قاعدة، والحزم والبايتات:

الطرفية — القواعد المحمَّلة حاليًا
sudo pfctl -s rules
# example output, trimmed
scrub-anchor "com.apple/*" all fragment reassemble
anchor "com.apple/*" all
block drop in log quick from <blocklist> to any

ذلك السطر com.apple/* ليس زخرفة. تحمّل Apple قواعدها الخاصة في مراسٍ (anchors) مسمّاة — مصطلح pf لمجموعة قواعد فرعية مكتفية بذاتها يمكن استبدالها دون إعادة تحميل كل شيء آخر. يستهدف خيار -a في pfctl مرسى محددًا، ووفق دليل الاستخدام، فإن استخدامه مع حرف بدل يفعّل الطباعة المتكررة للمراسي المتداخلة، وهذه هي الطريقة لرؤية ما حمّلته Apple نفسها إلى جانب أي شيء تضيفه أنت:

الطرفية — سرد كل مرسى محمَّل بشكل متكرر
sudo pfctl -a '*' -s rules
# example output, trimmed to the anchors that exist on a stock Mac

كتابة قاعدة اختبار وتحميلها

ملف مرسى بسيط يحظر عنوان IP واحدًا صادرًا، محفوظ باسم /etc/pf.anchors/test-block:

/etc/pf.anchors/test-block
block drop out quick on en0 proto tcp to 203.0.113.10 port 443

لتحميل ملف مرسى واحد، يقرأ pfctl -f القواعد من ملف، ووفق دليل استخدامه، يصف الملف بأنه يحتوي على وحدات ماكرو وجداول وخيارات وقواعد تصفية:

الطرفية — تحميل القاعدة وتأكيدها
sudo pfctl -f /etc/pf.anchors/test-block
sudo pfctl -s rules
block drop out quick on en0 proto tcp from any to 203.0.113.10 port = 443

لماذا لا يمكن أن يكون pf جدار حماية تطبيقاتك

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

لا فكرة لديه عن أي تطبيق أرسل الحزمة

تطابق قواعد pf على عنوان IP والمنفذ والبروتوكول والواجهة والاتجاه. لا يوجد حقل لـ«اسم العملية» أو «معرّف الحزمة» أو «توقيع الكود»، لأن pf يقع عند الطبقة التي توجد فيها الحزم لكن لا توجد فيها العمليات. تطبيقان مختلفان تمامًا يفتحان اتصالات TCP إلى العنوان والمنفذ نفسيهما لا يمكن تمييزهما بالنسبة لـ pf. إن أردت السماح لـ Slack بالوصول إلى مضيف بينما تحظر كل تطبيق آخر من الوصول إلى المضيف نفسه، لا يستطيع pf وحده التعبير عن تلك القاعدة.

القاعدة على اسم مضيف هي قاعدة على أيًا كان عنوان IP الذي كان لذلك الاسم وقت التحميل

كثيرًا ما تشير ملفات pf.conf إلى اسم مضيف من أجل الوضوح — block from evil.example.com. لكن ما يُحمَّل فعليًا ليس ذلك الاسم؛ بل أيًا كان العنوان الذي حُلّ إليه. يذكر دليل استخدام pf.conf من OpenBSD ذلك بوضوح: «تحليل اسم المضيف وترجمة الواجهة إلى عنوان يتمّان وقت تحميل مجموعة القواعد». لا يوجد بحث DNS وقت التشغيل أثناء تدفق الحركة — يحدث الاستبدال مرة واحدة، حين تشغّل pfctl -f، وتستمر القاعدة في مطابقة ذلك العنوان الواحد حتى تعيد تحميلها. هذا جيد بالنسبة لخادم بعنوان IP ثابت. لكنه ينهار لحظة أن يكون الاسم وراءه شبكة توصيل محتوى (CDN)، أو موازن تحميل سحابي، أو أي خدمة تُناوِب أو توازن التحميل عبر عناوين كثيرة — وهو ما يصف معظم الإنترنت في 2026. تضيق القاعدة المقصودة لحظر «هذه الخدمة» بصمت لتصبح «أيًا كان عنوان تلك الخدمة الذي أجاب حين حمّلت القاعدة»، وتمر الحركة إلى كل عنوان آخر يحلّه الاسم نفسه دون عائق.

لا مطالبات، لا حوار — مجرد مجموعة قواعد ثابتة

ليس لدى pf نموذج تفاعل. لا يستطيع إيقاف اتصال مؤقتًا وسؤال «يريد Mail الوصول إلى 51.x.x.x على المنفذ 993 لأول مرة — هل تسمح بذلك؟». إما أن يطابق قاعدة كتبتها بالفعل، أو ينحدر إلى الإعداد الافتراضي. يجب توقّع كل قرار وكتابته مسبقًا، بمصطلحات IP ومنفذ، قبل حدوث الحركة. لا يوجد ما يعادل مطالبة الاتصال الأول، لأن المطالبة تتطلب معرفة أي تطبيق يسأل، ولا تملك pf تلك المعلومة من الأساس.

إعدادك المكتوب يدويًا لا يصمد أمام تحديث

تعامل Apple ملف /etc/pf.conf والمراسي التي يحمّلها كإعداد يديره النظام مرتبط بداخليات macOS — مشاركة الإنترنت، وVPN، ومراسي جدار حماية التطبيقات نفسها تعتمد عليه جميعًا. تحديثات macOS حرة في إعادة كتابة ذلك الملف أو استبداله. إن حرّرته يدويًا لإضافة قواعدك الخاصة، فلا ضمان أن تصمد أمام التحديث التالي؛ وتكتشف ذلك بالطريقة الصعبة، بعد فوات الأوان، أن قاعدتك توقفت عن التطبيق بصمت. ملف إعداد يصونه شخص يدويًا ويكتب فوقه نظام التشغيل دوريًا مكان سيء للاحتفاظ فيه بالشيء الوحيد الذي كنت تهتم به فعليًا — «هل تحدث جهاز الـ Mac الخاص بي مع ذلك العنوان مجددًا».

لا عارض سجلات، لا سجل تاريخي، لا خريطة

يستطيع pf تسجيل الحزم المطابقة إلى واجهة زائفة، pflog0، إن تضمنت قاعدة الكلمة المفتاحية log — ظاهرة أعلاه في قاعدة قائمة الحظر من مخرجات -s rules السابقة. لكن ذلك السجل تدفق التقاط حزم، يُقرأ بـ tcpdump -i pflog0، لا سجلًا تاريخيًا قابلًا للبحث. لا يوجد عارض مدمج، ولا قائمة لكل تطبيق بما حُظر ومتى، ولا دولة أو منظمة مرتبطة بعنوان، ولا شيء يمكنك عرضه على أحد للإجابة عن «ماذا حاول هذا الـ Mac الوصول إليه الأسبوع الماضي». تحصل على حزم خام، وعليك بناء البقية بنفسك.

الطبقة التي بنتها Apple فعليًا لهذه المهمة

إجابة Apple نفسها على «أريد تصفية حركة جهاز الـ Mac الخاص بي لكل تطبيق» ليست pf — بل إطار عمل Network Extension، وتحديدًا مزوّدو مرشِّح المحتوى فيه. يصف توثيق مطوري Apple النموذج مباشرة: «يفحص مرشِّح محتوى شبكة على الجهاز محتوى شبكة المستخدم أثناء مروره عبر مكدس الشبكة، ويقرر ما إذا كان ينبغي حظر ذلك المحتوى أو السماح له بالمرور إلى وجهته النهائية»، ومزوّد بيانات مرشِّح — NEFilterDataProvider — «يستقبل محتوى شبكة المستخدم ويفحص ذلك المحتوى لتقرير ما إذا كان سيُحظر أو يُسمح به». تُمثَّل التدفقات ككائنات NEFilterFlow (بحالات ملموسة هي NEFilterBrowserFlow وNEFilterSocketFlow)، وهذه هي القطعة المفقودة التي لم يمتلكها pf أبدًا: كائن تدفق يمكن لتطبيق تصفية فحصه وربطه بالعملية التي فتحته، قبل تقرير التمرير أو الحظر.

هذا أيضًا سبب كون جدار حماية التطبيقات المدمج (المفتاح في إعدادات النظام) حيوانًا مختلفًا عن pf، لا واجهة أمامية له. يصفه دليل Apple نفسه بمصطلحات واردة فقط: فهو «يمكنه حماية جهاز الـ Mac الخاص بك من اتصال غير مرغوب فيه تبدأه حواسيب أخرى»، ويعمل بالسماح لك بـ«اختيار تطبيقات وخدمات، وتحديد ما إذا كان بإمكانها الوصول عبر جدار الحماية». لكل تطبيق، نعم — لكن فقط للاتصالات الواردة، وفقط عبر الآلية المحددة التي بنتها Apple لتلك المهمة الواحدة. إنه يجيب عن سؤال مختلف عن «ما الذي يرسله تطبيقي إلى الخارج».

ثلاث طرق لتصفية الحركة على جهاز Mac، وما يعرفه كل منها فعليًا
النهجيرى IP/المنفذيعرف أي تطبيقيتعامل مع عناوين IP المُعاد تسميتها/المُناوَبةيمكنه مطالبة المستخدمالاتجاه
pf (‏pfctl)نعملالا — يُحل مرة واحدة وقت التحميللاأي منهما، حسب القاعدة
جدار حماية التطبيقات (إعدادات النظام)لا (مفتاح على مستوى التطبيق)نعملا ينطبقلاوارد فقط
مرشِّح محتوى Network Extensionنعمنعم، عبر كائن التدفقنعم — يُقيَّم لكل تدفق حينعم، بواسطة التطبيق المبني عليهصادر ووارد

لا شيء من هذا يجعل pf عديم الفائدة. إن كنت تشغّل جهاز Mac كموجّه خفيف، أو تحتاج إلى رفض نطاق معروف بأنه سيئ على مستوى النواة بغض النظر عن أي عملية تسأل، أو تريد فهم ما تفعله ميزات مشاركة الإنترنت وVPN الخاصة بـ Apple نفسها خلف الكواليس، فإن pf هو الأداة الصحيحة والوحيدة لتلك المهمة، وpfctl -s rules / -s info هما الطريقة الصحيحة للنظر فيه. ما لم يكن pf ليفعله أبدًا هو الإجابة عن السؤال الذي يطرحه معظم الناس فعليًا: أي من تطبيقاتي يتحدث مع من، الآن، وهل يمكن أن يُسأل عني قبل أن يصل تطبيق جديد إلى ذلك.

دور FireAI وHisnLabs

pf and the built-in Application Firewall are both worth using — FireAI does not replace either; it fills the specific gap neither one can, by tying outbound decisions to the app’s code signature and asking before an unknown one gets a first connection.

FireAI هو منتج HisnLabs نفسها: جدار حماية بذكاء اصطناعي يعمل على جهاز Mac مباشرة. يعرض بلغة واضحة كل اتصال تجريه تطبيقاتك، ويترك لك القرار فيما يخرج من جهازك — ذكاؤه الاصطناعي يعمل محليًا، فلا يُرسَل ترافيكك إلينا ولا إلى أي جهة أخرى أبدًا. فريق أبحاث الأمن في HisnLabs هو من يحافظ على دقة هذه القرارات: يصنّف النطاقات بين قياس عن بُعد عادي وخدمة حقيقية، ويتتبّع بلد وشبكة كل اتصال، ويدرّب النموذج المحلي (ميزة Autopilot) على حركة اتصال حقيقية، دون أن يغادر أي شيء جهاز Mac.

يمكنك الاطلاع على القرارات التقنية وراء ذلك، أو تجربة FireAI لمدة 17 يومًا، على FireAI من HisnLabs.

المصادر