Cybersecurity16 مايو 20269 min read

إدارة الأسرار في التطبيقات: كيف تتوقف عن كتابة مفاتيح API داخل الكود

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

بقلم Innovation T Team


كل تقرير تحليل لاختراق (postmortem) يحتوي فصلاً مألوفاً: أحدهم عثر على بيانات اعتماد مكشوفة. في مستودع كود، في طبقة من طبقات Docker، في سجل CI، أو في لقطة شاشة أُرسلت على مجموعة WhatsApp الخاصة بالفريق. إدارة الأسرار ليست ترفاً تنظيمياً ولا بنداً شكلياً في قائمة الامتثال. إنها الفارق بين حادث محدود يمكن احتواؤه ومهاجم يمسك بمفاتيح قاعدة بيانات الإنتاج لديك.

لماذا لا تبقى الأسرار المكتوبة في الكود سرية أبداً

السر الذي يُرفع إلى الكود لم يعد سراً. إنه قنبلة موقوتة بإعدادات ظهور عامة.

هذه هي الأماكن التي تتسرب منها فعلياً:

  • سجل git. حذف المفتاح في commit جديد لا يغير شيئاً. الكائن القديم يبقى حياً في مخزن الكائنات، وفي كل نسخة clone، وفي كل fork، وفي ذاكرة التخزين المؤقت لخوادم CI. أمر git log -p يعثر عليه في ثوانٍ.
  • طبقات صور Docker. تنفيذ COPY .env . ثم RUN rm .env بعده يشحن السر مع الصورة رغم ذلك. الطبقات تراكمية بطبيعتها، وأي شخص يملك صلاحية سحب الصورة يستطيع تشغيل docker history واستخراجه.
  • سجلات CI. أمر env | sort نُسي في خطوة تصحيح أخطاء، إطار عمل يطبع الإعدادات عند الإقلاع، أو أداة اختبارات تُفرغ متغيرات البيئة عند الفشل. السجلات تُحفظ وتُرسل إلى أنظمة أخرى وتُفهرس.
  • حزم الواجهة الأمامية. أدوات البناء تُضمّن في حزمة المتصفح كل متغير مسبوق ببادئة العرض العام. نرى بانتظام مفاتيح خوادم تصل إلى المتصفح لأن أحدهم أعاد تسمية المتغير فقط لكي ينجح البناء، وأحياناً يكون المفتاح المكشوف مفتاح بوابة دفع محلية مثل Konnect أو مفتاح WhatsApp Business API الذي يعتمد عليه نشاطك التجاري بالكامل.
  • المزامنة مع أطراف خارجية. إضافات المحررات وأدوات النسخ الاحتياطي ومساعدات البرمجة بالذكاء الاصطناعي التي تفهرس مساحة عملك ستفهرس ملف .env أيضاً بكل بساطة.

الماسحات الآلية تراقب تدفق الأحداث العام على GitHub على مدار الساعة. من تجربتنا، مفتاح سحابي مكشوف يُرفع إلى مستودع عام يبدأ استغلاله خلال دقائق، لا أيام. وغالباً ما تكتشف الفرق الأمر عبر فاتورة AWS منتفخة بسبب أدوات تعدين العملات الرقمية.

نموذج التهديد بكل وضوح

أنت تدافع ضد ثلاثة أشياء:

  1. الاستخراج (exfiltration): مهاجم يقرأ السر من مكان كُتب فيه.
  2. إعادة الاستعمال (replay): مهاجم يملك السر ويستعمله من أي مكان وطوال مدة صلاحيته.
  3. نطاق الضرر (blast radius): بيانات اعتماد واحدة مسربة تفتح أبواباً أكثر بكثير مما يجب.

كل إجراء من الإجراءات أدناه يهاجم واحداً من هذه الثلاثة. التشفير أثناء التخزين يهاجم الاستخراج. مدد الصلاحية القصيرة (TTL) تهاجم إعادة الاستعمال. بيانات الاعتماد المحدودة النطاق والمخصصة لكل خدمة تهاجم نطاق الضرر. وأي أداة لا ترتبط بوضوح بواحد من هذه الثلاثة هي مجرد ديكور.

سلم النضج

لا تقفز مباشرة إلى تشغيل عنقود Vault كامل. اصعد السلم بتدرج مدروس.

المستوى 0: ملفات .env خارج git

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

المستوى 1: مخازن الأسرار في المنصة

استعمل المخزن الذي توفره منصتك أصلاً: AWS Secrets Manager أو SSM Parameter Store، أو GCP Secret Manager، أو Azure Key Vault، أو الأسرار المشفرة في Vercel أو Fly.io أو GitHub Actions. الأسرار مشفرة أثناء التخزين، وتُحقن وقت التشغيل، والوصول إليها محكوم عبر IAM. ولأغلب الفرق في منطقتنا التي تستضيف على مناطق أوروبية قريبة مثل باريس أو فرانكفورت، هذا الخيار متاح دون أي بنية إضافية. لمعظم الفرق التي تضم أقل من 20 مهندساً، هذا المستوى إذا نُفذ بإتقان يتفوق على Vault مُدار بشكل سيئ.

الانضباط الأساسي في هذا المستوى: التطبيق يقرأ الأسرار من متغيرات البيئة أو عبر SDK عند الإقلاع، ولا يقرأها أبداً من ملف داخل المستودع.

المستوى 2: إدارة مركزية للأسرار مع تحكم في الوصول وتدقيق

نظام مرجعي واحد لكل سر عبر كل البيئات. HashiCorp Vault أو OpenBao (الفرع مفتوح المصدر) أو Infisical أو Doppler. ما تكسبه مقارنة بالمستوى 1:

  • التوحيد: واجهة API واحدة ولغة سياسات واحدة عبر AWS وGCP والخوادم المحلية وCI.
  • التدقيق: كل عملية قراءة تُسجل مع الهوية والمسار والتوقيت. عندما يتسرب مفتاح، سجل التدقيق هو ما يسمح لك بتحديد حجم الحادث.
  • السياسات: خدمة الفوترة تستطيع قراءة billing/* ولا شيء غيره، والقاعدة مفروضة مركزياً.

المستوى 3: بيانات اعتماد ديناميكية قصيرة العمر

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

الأسرار الديناميكية: اقضِ على بيانات الاعتماد الثابتة

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

vault write database/roles/app-readonly \
  db_name=postgres \
  creation_statements="CREATE ROLE \"{{name}}\" WITH LOGIN PASSWORD '{{password}}' \
    VALID UNTIL '{{expiration}}'; \
    GRANT SELECT ON ALL TABLES IN SCHEMA public TO \"{{name}}\";" \
  default_ttl="1h" max_ttl="24h"

كل قراءة من database/creds/app-readonly تنشئ دوراً جديداً في Postgres يدمر نفسه ذاتياً بعد ساعة. الخصائص التي تحصل عليها دون مجهود إضافي:

  • نسب العمليات إلى أصحابها. استعلام بطيء صادر عن v-k8s-app-readonly-x7Hf؟ تعرف بدقة أي pod أطلقه.
  • الإلغاء الفوري. ألغِ الـ lease فتموت بيانات الاعتماد الآن، لا عند النشر القادم.
  • تسريبات بلا قيمة. بيانات اعتماد ظهرت في لقطة شاشة أثناء جلسة تصحيح أخطاء تنتهي صلاحيتها قبل أن يتمكن أي أحد من استعمالها.

النمط نفسه موجود لبيانات اعتماد AWS STS، ومفاتيح حسابات الخدمة في GCP، وشهادات SSH، وPKI. لكن المقابل حقيقي: يجب أن تتحمل قاعدة بياناتك دوراناً مستمراً للأدوار، وتحتاج أدوات تجميع الاتصالات (connection poolers) إلى منطق إعادة مصادقة، ويتحول Vault إلى بنية تحتية من الطبقة صفر. وهذا يقودنا إلى أنماط الفشل.

مشكلة السر صفر، وأنماط الفشل الأخرى

تتبنى الفرق نظام vault ثم تتعثر في الأشياء الأربعة نفسها:

  • السر صفر (secret zero). يحتاج التطبيق إلى بيانات اعتماد ليتخاطب مع الـ vault. إذا كانت هذه البيانات رمزاً ثابتاً في متغير بيئة، فقد نقلت المشكلة من مكان إلى آخر ولم تحلها. الحل هو هوية المنصة: رموز حسابات الخدمة في Kubernetes، أو مصادقة IAM في AWS، أو هوية الأجهزة في GCP. عبء العمل يثبت هويته بشيء تشهد عليه المنصة، لا بشيء لصقه إنسان.
  • الـ vault كنقطة فشل وحيدة. إذا توقف Vault وعجزت الـ pods عن الإقلاع، فقد حولت أداة أمنية إلى حادث توفر. شغّله بتوفر عالٍ حقيقي، وخزّن الـ leases مؤقتاً لدى العميل، واضبط مدد TTL بطول يكفي لتجاوز انقطاع قصير.
  • الارتداد إلى الفوضى. المهندسون تحت ضغط المواعيد ينسخون الأسرار من الـ vault ويعيدونها إلى ملفات .env بشكل مؤقت كما يقولون. اجعل المسار الرسمي هو المسار الأسهل: تكامل عبر SDK، أو حقن عبر sidecar، أو ملفات تُولد من قوالب وقت النشر.
  • سجلات تدقيق تُكتب ولا تُقرأ. سجل تدقيق لا ينبه أحداً هو وثيقة امتثال لا أكثر. فعّل التنبيهات على القراءات من هويات غير معتادة، والقراءات الجماعية، واستعمال الـ root token.

CI/CD: توقف عن تخزين مفاتيح السحابة في خط النشر

بيئة CI هي المكان الذي تذهب إليه بيانات الاعتماد الثابتة لتُسرق. مفتاح AWS_SECRET_ACCESS_KEY طويل العمر في إعدادات خط النشر يستطيع قراءته كل مشرف على المستودع، وكل action مخترقة، وكل حزمة تعتمد عليها وتحمل سكريبت postinstall.

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

permissions:
  id-token: write
  contents: read
steps:
  - uses: aws-actions/configure-aws-credentials@v4
    with:
      role-to-assume: arn:aws:iam::123456789012:role/deploy-prod
      aws-region: eu-west-1

قيّد سياسة الثقة في IAM على منظمتك ومستودعك وفرعك بالضبط. مهمة تعمل على main في مستودعك تستطيع النشر، ومهمة على fork لا تستطيع، والضمان هنا تشفيري. GitHub Actions وGitLab CI وCircleCI تدعم كلها هذا النمط مع AWS وGCP وAzure. وإذا كنت تبني وضعية أمان خط النشر لديك بشكل أشمل، فإن دليلنا حول خطوط DevSecOps يشرح موقع إدارة الأسرار في السلسلة الأكبر.

اكتشف التسريبات قبل وصولها إلى الإنتاج

الوقاية تتفوق على الاستجابة، والأدوات مجانية. ركّب ثلاث شبكات أمان متتالية:

1. الفحص قبل الـ commit. أداة Gitleaks تفحص الفرق المجهز للـ commit في أقل من ثانية:

repos:
  - repo: https://github.com/gitleaks/gitleaks
    rev: v8.24.0
    hooks:
      - id: gitleaks

2. الحماية عند الدفع. خاصية secret scanning مع push protection في GitHub تحجب عملية الدفع من جهة الخادم عندما تطابق نمط بيانات اعتماد معروفة. فعّلها على كل مستودع، بما في ذلك المستودعات الخاصة. وGitLab يوفر ما يعادلها.

3. فحص التاريخ والمخرجات. شغّل TruffleHog أو Gitleaks على كامل تاريخ git وصور الحاويات ومخرجات البناء وفق جدولة دورية. الاكتشافات المتحقق منها (حيث تتصل الأداة فعلياً بالمزود للتأكد أن المفتاح ما يزال فعالاً) تقلص ضجيج الإنذارات الكاذبة بشكل كبير.

لا شيء من هذا يغني عن تصميم واجهات API والخدمات بحيث تكون الأسرار محدودة النطاق من البداية. مقالنا حول أفضل ممارسات أمان API يتعمق أكثر في تقييد نطاق المفاتيح وتدويرها عند حدود الـ API.

عندما يتسرب المفتاح رغم كل شيء: الساعة الأولى

افترض أن التسريب سيحدث. خطة التنفيذ، بالترتيب:

  1. ألغِ أولاً وحقق ثانياً. لحظة تأكيد الانكشاف، اقتل بيانات الاعتماد. لا تنتظر نافذة صيانة. ألم توقف الخدمة قابل للاسترداد، أما البيانات المستخرجة فلا.
  2. أصدر البديل. أنشئ بيانات الاعتماد الجديدة عبر مدير الأسرار، وبنطاق أضيق من القديمة. هذه هي اللحظة المناسبة لإصلاح الصلاحيات المفرطة التي كنت تؤجل إصلاحها.
  3. حدد حجم الضرر. استخرج سجلات التدقيق لكامل فترة انكشاف بيانات الاعتماد، لا منذ لحظة الاكتشاف فقط. في AWS يعني ذلك استعلامات CloudTrail على معرف مفتاح الوصول. ابحث عن عناوين IP ومناطق واستدعاءات API غير مألوفة.
  4. نظّف التاريخ، لكن اعتبر المفتاح محروقاً. أعد كتابة التاريخ عبر git filter-repo ثم ادفع بالقوة، لكن افهم أن هذا تنظيف وليس معالجة. النسخ والـ forks ما تزال تحتفظ به. بيانات الاعتماد ميتة في كل الحالات، وهذا بالضبط هدف الخطوة 1.
  5. أصلح المسار، لا الشخص. السر وصل إلى الكود لأن المسار الآمن كان أصعب من المسار غير الآمن. أضف الـ pre-commit hook، واربط مدير الأسرار، وأغلق الثغرة.

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

إطار لاتخاذ القرار

طابق الأداة مع حجم الفريق، لا مع ما يُعرض في المؤتمرات:

  • مطور منفرد أو فريق صغير جداً، سحابة واحدة: مدير الأسرار الخاص بسحابتك مع OIDC في CI. عمل عصر يوم واحد يحقق أغلب القيمة، وهذا ينطبق على معظم الشركات الناشئة في تونس والمنطقة التي بدأت للتو رحلة الرقمنة.
  • فريق في طور النمو، سحابة أو اثنتان، مع Kubernetes: مديرو الأسرار السحابيون كخلفية، مع External Secrets Operator للمزامنة داخل العنقود، وpush protection على كل مستودع.
  • تعدد سحابات ومتطلبات امتثال وأعباء عمل تعمل على مدار الساعة: Vault أو OpenBao مع مصادقة عبر هوية المنصة، وبيانات اعتماد ديناميكية لقواعد البيانات والوصول السحابي، وتنبيهات مربوطة بسجل التدقيق.
  • قطاعات منظمة أو أهداف عالية القيمة: كل ما سبق، إضافة إلى مدد TTL قصيرة كسياسة ملزمة، وتمارين تسريب فصلية، وتدوير أسرار تتحقق منه الأتمتة لا تذكير في التقويم. وهذا هو المستوى المتوقع من بنك أو شركة اتصالات أو أي جهة في المنطقة تعالج معطيات شخصية خاضعة لهيئات حماية البيانات مثل INPDP في تونس.

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

كيف تساعدك Innovation T

تصمم Innovation T وتشغّل بنى إدارة الأسرار لفرق عبر أوروبا وشمال إفريقيا: نشر Vault وOpenBao بتوفر عالٍ حقيقي، واتحاد OIDC لخطوط CI/CD، وبيانات اعتماد ديناميكية لقواعد البيانات، واكتشاف تسريبات مدمج في خط النشر بدل أن يُضاف بعد وقوع الحادث. نقلنا فرقاً كاملة بعيداً عن المفاتيح المكتوبة في الكود دون أي انقطاع في الإنتاج، ونترك خلفنا أدلة تشغيل يستعملها مهندسوك فعلاً.

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

#إدارة الأسرار#Vault#مفاتيح API#DevSecOps

جاهز للبناء مع Innovation T؟

سواء كان الأمر يتعلق بالأمن أو النمو أو الهندسة، يمكن لفريقنا مساعدتك على تنفيذه بإتقان.