الدروس
متوسط الأمان

إدارة الأسرار وملفات .env ومفاتيح API: من التطوير المحلي إلى الإنتاج الآمن

من ملف .env إلى Secret Manager والهوية المُدارة: أين يوجد المفتاح، ومن يقرؤه، وكيف تغيّره إذا تسرّب — وكيف تستغني عنه متى أمكن.

د
Devsamhan
١٠ أكتوبر ٢٠٢٦ ٢٠ دقيقة قراءة ٣ تمارين الأمان — Devsamhan
سلّم أمان الأسرار: من Hardcoded إلى Managed Identity

من أكثر الأخطاء شيوعًا في مشاريع الفايب كودنق أن يبدأ المطور بكتابة:

OPENAI_API_KEY=...
SUPABASE_SERVICE_ROLE_KEY=...
DATABASE_PASSWORD=...

ثم يضع الملف في المشروع ويظن أن المشكلة انتهت.

أو الأسوأ:

const apiKey = "sk-...";

داخل الكود نفسه.

في البداية قد يعمل كل شيء بصورة طبيعية.

لكن السؤال الحقيقي ليس:

هل التطبيق يستطيع قراءة المفتاح؟

بل:

أين يوجد المفتاح؟
من يستطيع قراءته؟
هل يمكن تسريبه؟
هل يستطيع أي شخص استخدامه خارج التطبيق؟
ماذا يحدث إذا ظهر في GitHub أو Logs أو ملف Build؟
وهل يمكننا إلغاءه وتغييره دون تعطيل المنتج؟

هنا ندخل إلى موضوع إدارة الأسرار — Secrets Management.

وهو موضوع أكبر بكثير من ملف .env.

١. ما المقصود بـSecret؟

ليست كل قيمة في إعدادات المشروع سرًا.

هناك فرق بين:

Configuration

إعدادات تشغيلية مثل:

APP_ENV=production
API_BASE_URL=https://api.example.com
LOG_LEVEL=info
FEATURE_CHAT_ENABLED=true

هذه قد لا تكون حساسة.

وبين:

Secrets

قيم تسمح لمن يحصل عليها بتنفيذ عمليات حساسة، مثل:

DATABASE_PASSWORD=...
OPENAI_API_KEY=...
STRIPE_SECRET_KEY=...
JWT_PRIVATE_KEY=...
SUPABASE_SERVICE_ROLE_KEY=...

إذا تسربت هذه القيم فقد يستطيع المهاجم:

وتوصي Microsoft بالفصل بين الأسرار والإعدادات العادية، وعدم استخدام خزائن الأسرار لتخزين كل إعداد في النظام بلا حاجة. (learn.microsoft.com)

قاعدة مهمة

ليس كل Config سرًا، لكن كل Secret يحتاج إلى حماية أكثر من مجرد وضعه في ملف إعدادات.

٢. الخطأ الأول: كتابة المفتاح داخل الكود

من أسوأ الطرق:

const stripeSecretKey =
  "sk_live_XXXXXXXXXXXXXXXX";

أو:

const openAiKey = 'sk-...';

لماذا؟

لأن السر أصبح جزءًا من:

حتى إذا حذفته بعد ذلك، قد يبقى داخل سجل Git.

لذلك القاعدة الأولى:

لا تكتب الأسرار داخل الكود.

٣. ماذا يحدث إذا رفعت Secret إلى GitHub ثم حذفته؟

لنفترض أنك ارتكبت الخطأ التالي:

commit 1
→ يحتوي API_KEY

ثم لاحظت المشكلة وحذفت السطر:

commit 2
→ لا يحتوي API_KEY

هل انتهت المشكلة؟

لا.

لأن المفتاح قد يبقى في:

Git history

وقد يكون:

عند تسرب Secret، لا تتعامل معه على أنه «مخفي الآن».

تعامل معه على أنه:

Compromised (تم كشفه أو إفشاؤه)

والإجراء الصحيح:

  1. ألغِ المفتاح القديم.
  2. أنشئ مفتاحًا جديدًا.
  3. حدّث الخدمات.
  4. راقب Logs والاستخدام.
  5. نظف Git History عند الحاجة.
  6. أضف Secret Scanning حتى لا يتكرر الخطأ.

Microsoft توصي باعتبار الأسرار Hardcoded (مكتوبة بالكود) المكتشفة معرضة للخطر واستبدالها بدل الاكتفاء بحذفها من الكود. (learn.microsoft.com)

٤. ما هو ملف .env؟

ملف .env هو ملف نصي يحتوي عادةً على إعدادات البيئة:

OPENAI_API_KEY=sk-...
DATABASE_URL=postgres://...
APP_ENV=development

ثم يقرأ التطبيق هذه القيم أثناء التشغيل.

مثلًا في Node.js:

process.env.OPENAI_API_KEY

الفكرة جيدة لأنها تفصل القيم عن الكود.

وهذا يتفق مع مبدأ معروف في Twelve-Factor App: يجب فصل الإعدادات التي تختلف بين البيئات عن Source Code. (12factor.net)

لكن توجد مشكلة مهمة:

ملف .env ليس خزنة أسرار.

إنه مجرد ملف نصي.

٥. هل .env آمن؟

الإجابة الدقيقة:

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

لأن .env قد:

ولهذا تحذر Microsoft من الاعتماد على ملفات .env لحفظ الأسرار الحساسة في سيناريوهات الإنتاج، وتوصي باستخدام خزائن أسرار أو هوية مُدارة بدل ذلك. (learn.microsoft.com)

٦. كيف تستخدم .env بطريقة صحيحة في التطوير؟

في جهاز المطور يمكن استخدام:

.env.local

مثلًا:

OPENAI_API_KEY=
DATABASE_URL=
STRIPE_SECRET_KEY=

ثم أضف الملفات الحساسة إلى:

.env
.env.*
!.env.example

وأضف ملفًا آمنًا للمستودع:

.env.example

يحتوي أسماء المتغيرات فقط:

OPENAI_API_KEY=
DATABASE_URL=
STRIPE_SECRET_KEY=

هذا يساعد أي مطور جديد على معرفة ما يحتاج إليه دون أن يرى القيم الحقيقية.

ما الفائدة؟

يمكنك رفع:

.env.example

إلى Git.

لكن لا ترفع:

.env.local

٧. .gitignore ليس نظام حماية كاملًا

هذه نقطة مهمة.

إذا أضفت:

.env

فهذا يمنع Git عادةً من إضافة الملف في المستقبل.

لكنه لا يحذف Secret سبق أن دخل Git History.

كما يمكن للمستخدم تجاوز Gitignore يدويًا.

لذلك .gitignore هو:

طبقة وقائية جيدة

وليس:

Secret Manager

٨. الفرق بين .env وEnvironment Variables

كثير من المطورين يعتبرهما الشيء نفسه.

لكن الفرق مهم.

.env

ملف موجود على القرص:

.env

Environment Variable

قيمة موجودة في بيئة العملية أثناء التشغيل:

OPENAI_API_KEY

يمكن أن تأتي Environment Variable من:

إذن:

.env مجرد طريقة واحدة لتوفير Environment Variables.

٩. هل Environment Variables آمنة؟

أفضل من Hardcoding.

لكن ليست حماية مطلقة.

قد تتسرب عبر:

Google Cloud تحذر من أن تمرير الأسرار عبر الملفات أو Environment Variables قد يؤدي إلى تسربها بسبب Misconfiguration أو Debugging، وتوصي عند الإمكان باستخدام Secret Manager API مباشرة. (cloud.google.com)

إذن التدرج يصبح:

Hardcoded secret
    ↓
.env
    ↓
Environment variable
    ↓
Secret Manager

لكن ما زال هناك مستوى أفضل سنصل إليه لاحقًا.

١٠. ما هو Secret Manager؟

Secret Manager هو خدمة مخصصة لحفظ وإدارة الأسرار.

من أشهر الأمثلة:

بدل وضع:

DATABASE_PASSWORD=supersecret

داخل خادمك، يصبح السر محفوظًا داخل Vault:

prod/database/password

والتطبيق يطلبه عند الحاجة وفق صلاحيات محددة.

١١. ما الذي يضيفه Secret Manager؟

عادةً يوفر مزايا مثل:

AWS توصي باستخدام Secrets Manager لحفظ Credentials والمعلومات الحساسة، مع تطبيق Rotation وLeast Privilege ومراقبة الوصول. (docs.aws.amazon.com)

وتوصي Azure باستخدام Key Vault للأشياء مثل:

١٢. كيف يعمل Secret Manager؟

التصميم البسيط:

Application
    ↓
Authenticates using its identity
    ↓
Secret Manager
    ↓
Returns allowed secret

بدل:

Application
→ reads password from local .env file

الفرق أن Secret Manager يستطيع معرفة:

وهذا مهم جدًا في الإنتاج.

١٣. هل Secret Manager أفضل من .env دائمًا؟

ليس بالضرورة لكل حالة.

للتطوير المحلي البسيط:

.env.local

قد يكون أسهل وأسرع.

لكن في Production:

Secret Manager

غالبًا أفضل.

لأنك تحصل على إدارة مركزية بدل توزيع أسرار نصية بين:

لكن Secret Manager يضيف تعقيدًا أيضًا:

لذلك لا تضف Vault إلى مشروع صغير فقط لأن الكلمة تبدو احترافية.

استخدمه عندما تكون هناك أسرار إنتاج حقيقية تحتاج إدارة.

١٤. مقارنة .env وSecret Manager

العنصر.envSecret Manager
سهل للتطوير المحليممتازأقل بساطة
مناسب للإنتاجمحدودممتاز
Plain textغالبًا نعملا في التخزين المركزي
Audit Logsلانعم
Versioningلانعم
Rotationيدويقابل للأتمتة
صلاحيات دقيقةلانعم
فصل البيئاتيدويأفضل
إلغاء السريدويمركزي
معرفة من قرأ السرلاغالبًا نعم

١٥. لكن الشركات الكبرى توصي بشيء أفضل من Secret Manager

هذه أهم نقطة في الدرس.

أفضل طريقة لحماية Secret هي:

ألا يكون لديك Secret طويل العمر أصلًا.

مثال تقليدي:

Application
→ DATABASE_PASSWORD
→ Database

هذا يعني أن هناك كلمة مرور يجب:

أما في Cloud الحديثة فيمكن أن يكون:

Application Identity
→ Identity Provider
→ Temporary Token
→ Database

لا توجد كلمة مرور طويلة العمر.

١٦. Managed Identity

Microsoft توصي باستخدام Managed Identity عندما يكون التطبيق داخل Azure ويمكنه المصادقة مباشرة إلى خدمة أخرى.

مثلًا:

Azure App
→ Managed Identity
→ Azure SQL

بدل:

Azure App
→ DATABASE_PASSWORD
→ Azure SQL

Microsoft توصي صراحة بالابتعاد عن Secret-based authentication عند إمكانية استخدام الهوية المُدارة أو Credentials قصيرة العمر. (learn.microsoft.com)

١٧. Workload Identity

الفكرة نفسها موجودة لدى Google Cloud عبر:

Workload Identity Federation

فبدل إنشاء Service Account Key طويل العمر وحفظه في GitHub:

GitHub
→ JSON service account key
→ Google Cloud

يمكن أن يصبح:

GitHub Actions
→ OIDC
→ Google Cloud Identity
→ temporary access

بدون ملف Key دائم. (cloud.google.com)

١٨. ماذا عن AWS؟

AWS لديها الفكرة نفسها عبر:

الهدف واحد:

لا تستخدم Access Key طويلة العمر إذا كانت الخدمة تستطيع الحصول على Temporary Credentials تلقائيًا.

١٩. إذن ما أفضل ترتيب؟

يمكن التفكير فيه بهذا الشكل:

Hardcoded Secret
        ↓
.env
        ↓
Hosting Environment Variable
        ↓
Secret Manager
        ↓
Managed / Workload Identity

كلما نزلنا إلى الأسفل:

٢٠. أفضل Secret هو Secret غير موجود

هذه العبارة تختصر الموضوع كله.

إذا استطعت استخدام:

temporary token

بدل:

permanent password

فاستخدمه.

إذا استطعت استخدام:

workload identity

بدل:

service account JSON key

فاستخدم الهوية.

إذا استطعت استخدام:

OIDC

بدل:

cloud access key

فهذا أفضل عادةً.

٢١. GitHub Actions: أين نضع الأسرار؟

من الأخطاء الشائعة:

env:
  DATABASE_PASSWORD: "my-password"

داخل Workflow.

لا تفعل ذلك.

GitHub توفر:

Repository Secrets
Environment Secrets
Organization Secrets

وتستخدمها مثل:

${{ secrets.DATABASE_PASSWORD }}

GitHub توصي باستخدام Secrets للقيم الحساسة، وليس Variables العادية. (docs.github.com)

٢٢. Environment Secrets مهمة جدًا

يمكن أن يكون لديك:

development
staging
production

وكل بيئة لديها أسرار مختلفة.

مثلًا:

staging
→ STRIPE_TEST_KEY

production
→ STRIPE_LIVE_KEY

وهذا أفضل من استخدام Secret واحدة للجميع.

GitHub Environments تسمح كذلك بفرض قواعد حماية مثل Required Reviewers قبل وصول Workflow إلى Secrets الإنتاج. (docs.github.com)

٢٣. لكن الأفضل: لا تحفظ Cloud Key في GitHub أصلًا

بدل:

GitHub Secret
→ AWS_ACCESS_KEY_ID
→ AWS_SECRET_ACCESS_KEY

يمكن استخدام:

GitHub Actions
→ OIDC
→ cloud provider
→ temporary token

وهذا يقلل الاعتماد على Credentials طويلة العمر.

وهذا الاتجاه تدعمه Microsoft وGoogle ومزودو Cloud الآخرون.

٢٤. افصل Development وStaging وProduction

من الأخطاء الكبيرة استخدام المفتاح نفسه في جميع البيئات:

Development
Staging
Production
      ↓
 SAME_SECRET

إذا تسرب المفتاح من جهاز مطور:

أصبحت Production في خطر.

الأفضل:

Development
→ dev credentials

Staging
→ staging credentials

Production
→ production credentials

Google توصي بفصل بيئات Production وStaging في مشاريع منفصلة عندما يكون ذلك مناسبًا لتقليل Blast Radius. (cloud.google.com)

كما توصي Microsoft بفصل Key Vaults بحسب التطبيق والبيئة عند الحاجة. (learn.microsoft.com)

٢٥. لا تستخدم Secret واحدة لكل الخدمات

تصميم سيئ:

API Server ┐
Cron       ├── SAME_DATABASE_ADMIN_PASSWORD
Worker     ┘

إذا تسربت:

الأفضل:

API Server
→ credential A

Worker
→ credential B

Cron
→ credential C

مع أقل صلاحيات لكل واحد.

Microsoft توصي بفصل Credentials حسب Consumer وعدم مشاركة Secret واحدة بين تطبيقات متعددة دون حاجة. (learn.microsoft.com)

٢٦. Least Privilege

لا يكفي أن يكون السر داخل Vault.

تخيل أنك فعلت:

Secret Manager
✓

لكن أعطيت كل خدمة:

Read all secrets

الآن أي Service مخترقة تستطيع قراءة كل شيء.

الصحيح:

Payment service
→ payment secrets only

Email worker
→ email secret only

AI service
→ AI provider secret only

وهذا يسمى:

Least Privilege

أي:

أعطِ كل جهة أقل صلاحية تحتاج إليها فقط.

وهذه من التوصيات المتكررة لدى AWS وGoogle وMicrosoft وGitHub.

٢٧. Rotation: ماذا تعني؟

Rotation تعني تغيير Credential دوريًا.

لكن Rotation السيئة:

change password
→ production breaks

Rotation الجيدة:

Create new secret
↓
Allow old + new temporarily
↓
Deploy consumers using new secret
↓
Verify
↓
Revoke old secret

Azure توصي بتدوير الأسرار وباستخدام أكثر من Credential عندما يكون ذلك ضروريًا لتحقيق Rotation بلا توقف. (learn.microsoft.com)

٢٨. لا تنتظر Rotation إذا تسرب المفتاح

إذا اكتشفت تسرب Secret:

لا تقل:

موعد Rotation بعد شهر.

نفذ فورًا:

REVOKE
↓
REPLACE
↓
INVESTIGATE

كل دقيقة يبقى فيها المفتاح صالحًا قد تسمح باستخدامه.

٢٩. Versioning

Secret Manager يمكن أن يحتفظ بنسخ:

database-password
  version 1
  version 2
  version 3

وهذا مفيد عند Rotation.

لكن يجب أن تتجنب أن يعتمد التطبيق عشوائيًا على:

latest

في سيناريو حساس دون فهم.

قد يكون من الأفضل أحيانًا تثبيت Version محددة ثم تحديثها بصورة مدروسة.

٣٠. Audit Logs

ميزة مهمة جدًا لا توفرها .env.

في Secret Manager يمكن أن تعرف:

service A read secret X at time Y

هذا يساعد في:

في ملف .env لا تعرف من قرأه.

٣١. لا تطبع الأسرار في Logs

يمكن أن تستخدم أفضل Secret Manager في العالم ثم تكتب:

console.log(process.env);

وتكشف كل شيء.

أو:

console.log(config);

فتظهر:

DATABASE_PASSWORD=...
OPENAI_API_KEY=...

داخل Logs.

الحل:

٣٢. لا تمرر السر في Command Line بلا حاجة

مثل:

deploy --password mysecret

قد يظهر السر في:

الأفضل استخدام الوسيلة التي تدعمها الأداة مثل:

GitHub توصي بتجنب تمرير الأسرار مباشرة في Command Line عند وجود بدائل أكثر أمانًا. (docs.github.com)

٣٣. أهم قاعدة لمطوري Flutter والويب: لا يوجد Secret حقيقي داخل التطبيق

هذه من أهم النقاط.

تخيل أنك كتبت:

const apiKey = String.fromEnvironment(
  'SECRET_API_KEY',
);

ثم بنيت تطبيق Flutter.

قد تقول:

المفتاح ليس في Source Code، إذن هو آمن.

لكن إذا أصبح السر جزءًا من التطبيق النهائي:

APK
IPA
Desktop binary
Web JavaScript

فيجب افتراض أن المستخدم يستطيع استخراجه.

لأن المستخدم يملك Binary.

٣٤. Client لا يستطيع حماية Secret دائم

إذا كان لديك:

Flutter app
→ OpenAI secret API key

فهذا تصميم خطير.

الأفضل:

Flutter app
↓
Your backend
↓
OpenAI API

المفتاح يبقى في الخادم.

التطبيق يرسل طلبًا إلى Backend الذي:

٣٥. ماذا عن Web Frontend؟

الأمر أكثر وضوحًا.

أي Secret تضعها في:

JavaScript bundle

يستطيع المستخدم غالبًا رؤيتها من المتصفح.

حتى إذا كانت في:

.env

أثناء Build.

إذا كانت Build Tool تحقنها في Frontend، فقد أصبحت Public.

وهذا من أكثر الأخطاء انتشارًا:

المطور يعتقد أن .env يعني Secret.

لكن إذا القيمة وصلت إلى Client Bundle، انتهت السرية.

٣٦. Public Key ليست Secret Key

ليس كل API Key سريًا.

قد توفر خدمة مفتاحًا مثل:

pk_...

ومفتاحًا آخر:

sk_...

مثلًا:

STRIPE_PUBLISHABLE_KEY=pk_...
STRIPE_SECRET_KEY=sk_...

الأول مصمم للعميل.

الثاني للخادم فقط.

كذلك بعض الخدمات توفر:

ويكون الأمان الحقيقي معتمدًا على:

لذلك لا تسأل فقط:

هل هذا API Key؟

بل:

هل وثائق المزود تقول إنه Public أم Secret؟

٣٧. مثال مهم: Supabase

قد يحتوي مشروع Supabase على:

anon/public key

ومفتاح:

service role

الفرق بينهما كبير.

الـpublic/anon key مصمم ليكون مستخدمًا في Client ضمن نموذج أمان يعتمد على RLS.

أما:

service role key

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

إذا وضعته في Flutter أو Web:

يجب اعتباره متسربًا.

٣٨. Secret Scanning

لا تعتمد على الانتباه البشري فقط.

استخدم أدوات تبحث عن أنماط الأسرار في الكود.

مثل:

الهدف اكتشاف:

sk_live_...
AWS access key
private key
database password

قبل وصولها إلى Production.

٣٩. ماذا تفعل إذا اكتشف Secret Scanner مفتاحًا؟

لا تقل:

False positive غالبًا.

افحصه.

إذا كان حقيقيًا:

  1. ألغِ المفتاح.
  2. أنشئ واحدًا جديدًا.
  3. ابحث عن مكان استخدامه.
  4. افحص Git History.
  5. افحص CI logs.
  6. افحص Artifact.
  7. راقب مزود الخدمة للاستخدام الغريب.

٤٠. لا تجعل Secrets تظهر في رسائل الخطأ

مثال سيئ:

Failed to connect to:
postgres://admin:password123@db.example.com

وصل Connection String كاملة إلى:

الأفضل:

Database connection failed.
host=db.example.com
credential=[REDACTED]

٤١. هل نخزن Secrets في قاعدة البيانات؟

أحيانًا تحتاج إلى تخزين:

لا تخزنها Plain Text بلا حماية إذا كانت حساسة.

قد تحتاج إلى:

وإذا كان النظام لا يحتاج لاسترجاع القيمة الأصلية، لا تخزنها أصلًا.

مثل كلمات المرور:

لا تُشفّر فقط، بل تستخدم Password Hashing مناسبًا.

٤٢. Encryption لا يلغي مشكلة المفاتيح

قد تقول:

سأشفّر الأسرار داخل قاعدة البيانات.

ممتاز.

لكن السؤال يصبح:

أين مفتاح فك التشفير؟

إذا وضعت:

MASTER_KEY

داخل Source Code، عدنا إلى البداية.

لذلك أنظمة مثل KMS وKey Vault تساعد في إدارة مفاتيح التشفير نفسها.

٤٣. Secret Manager وKMS ليسا الشيء نفسه

بصورة مبسطة:

Secret Manager

مناسب لحفظ:

API key
password
token
connection string

KMS

مناسب لإدارة مفاتيح تشفير تستخدم في:

encrypt/decrypt data
signing
key operations

قد يعمل النظامان معًا.

لا تستخدم KMS كمخزن نصوص عشوائي إذا كان Secret Manager هو الأداة المناسبة.

٤٤. ماذا نضع في Secret Manager؟

أمثلة جيدة:

Database password
Third-party API secret
Private signing key
Webhook signing secret
OAuth client secret
SMTP password

أمثلة قد لا تحتاجه:

APP_NAME
LOG_LEVEL
PUBLIC_API_URL
FEATURE_FLAG

ضع Config العادية في نظام Configuration.

وأبقِ Vault للأشياء الحساسة.

٤٥. هل يجب استدعاء Secret Manager مع كل Request؟

غالبًا لا.

إذا كانت كل API Request تفعل:

call Secret Manager
→ get key
→ call database

فقد تزيد:

يمكن للتطبيق:

  1. قراءة Secret عند التشغيل.
  2. الاحتفاظ بها في ذاكرة العملية.
  3. تحديثها عند Rotation أو بعد TTL مناسب.

Azure توصي بتقليل عمليات جلب Key Vault باستخدام Caching مناسب مع دعم التحديث عند تغير Secret. (learn.microsoft.com)

لكن:

لا تكتب الـcache على القرص بلا حماية.

٤٦. كيف أبني استراتيجية Secrets لمشروع صغير؟

لنفترض أنك تبني تطبيقًا باستخدام:

Flutter
Supabase
OpenAI
GitHub Actions
VPS

يمكن أن يكون التصميم:

Flutter

يحتوي فقط على القيم المسموح أن تكون Public.

لا يحتوي:

OpenAI secret
Supabase service role
database admin password

Backend

يحصل على الأسرار من:

Secret Manager

أو Environment محمية في الاستضافة الصغيرة كبداية.

GitHub Actions

يستخدم:

Environment Secrets

أو الأفضل OIDC إذا كانت منصة النشر تدعمه.

Development

يستخدم:

.env.local

بمفاتيح Development منفصلة.

٤٧. مثال على فصل البيئات

Development

database-dev
openai-dev
stripe-test

Staging

database-staging
openai-staging
stripe-test-2

Production

database-prod
openai-prod
stripe-live

ولا تجعل المطور المحلي يستخدم:

stripe-live

لمجرد أنه أسهل.

٤٨. ماذا عن فريق العمل؟

إذا انضم مطور جديد، لا ترسل له:

.env

على WhatsApp.

ولا تضع ملف:

prod-secrets.txt

في Google Drive للجميع.

الأفضل أن تعطي الشخص:

وحين يغادر الفريق:

remove identity

بدل تغيير عشرين Password لأن الجميع كان يستخدم الحساب نفسه.

٤٩. الحسابات المشتركة مشكلة

مثال سيئ:

admin@company.com
password shared by 7 developers

إذا حدث شيء:

من فعل ذلك؟

لا تعرف.

استخدم Identities منفصلة.

وسجل Audit Logs.

٥٠. أسرار الفايب كودنق والذكاء الاصطناعي

هناك خطر جديد:

قد تنسخ إلى مساعد البرمجة:

Here is my production .env:
...

حتى يستطيع حل المشكلة.

لا تفعل ذلك بلا حاجة.

الأفضل:

DATABASE_URL=[REDACTED]
OPENAI_API_KEY=[REDACTED]

أو اطلب من الأداة قراءة Secret من Environment دون طباعتها.

القاعدة:

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

٥١. لا تجعل المساعد يطبع Secret للتأكد أنها موجودة

أمر سيئ:

Print the API key so I can verify it.

الأفضل:

Verify that OPENAI_API_KEY is present and non-empty.
Do not print or expose the value.

والنتيجة:

OPENAI_API_KEY: configured

وليس:

OPENAI_API_KEY=sk-xxxxxxxx

٥٢. Prompt عملي لمراجعة أسرار مشروعك

✅
تمرين ١

يمكنك إعطاء المساعد البرمجي هذا الأمر:

Act as a senior application security engineer.

Audit this repository for secret-management risks.

Do not print, expose, decode, or copy any secret values.

Inspect for:

- hardcoded API keys,
- passwords,
- tokens,
- private keys,
- service-role keys,
- database credentials,
- .env files tracked by Git,
- secrets exposed to frontend/mobile builds,
- production credentials used in development,
- secrets printed to logs,
- secrets passed in command-line arguments,
- shared credentials across services,
- missing rotation strategy,
- missing secret scanning,
- and overly broad access to secret stores.

Classify every finding as:

- confirmed,
- suspected,
- or safe by design.

For every confirmed finding report:

1. File and location.
2. Type of secret exposure.
3. Why it is dangerous.
4. Whether the secret should be considered compromised.
5. Immediate containment action.
6. Recommended long-term design.
7. Verification required after remediation.

Do not modify production systems.
Do not rotate credentials automatically.
Do not reveal secret values in the report.

٥٣. Prompt لتحويل .env إلى تصميم إنتاجي

✅
تمرين ٢
Review the current environment-variable and secret-management design.

Classify every variable into:

1. public configuration,
2. sensitive configuration,
3. secret,
4. credential that should be replaced by workload identity if possible.

For every item recommend one of:

- keep in public configuration,
- keep in local .env only,
- platform environment secret,
- secret manager,
- managed identity / workload identity / OIDC.

Then design separate handling for:

- development,
- staging,
- production,
- CI/CD.

Apply least privilege.

Do not move every configuration value into a secret manager.
Do not expose any existing secret values.

٥٤. قائمة فحص قبل نشر التطبيق

✅
تمرين ٣

Source Code

  • هل يوجد Secret داخل الكود؟
  • هل يوجد Password في README؟
  • هل يوجد Private Key؟
  • هل توجد قيم حقيقية داخل .env.example؟
  • هل Secret Scanner يعمل؟

.env

  • هل .env داخل .gitignore؟
  • هل دخل Git سابقًا؟
  • هل Development تستخدم Credentials خاصة بها؟
  • هل ملفات Production موجودة على أجهزة المطورين بلا حاجة؟

Frontend

  • هل توجد Secret داخل JavaScript؟
  • هل Flutter يحتوي Service Role Key؟
  • هل APK/IPA يحتوي Credential حساسة؟
  • هل القيمة مصممة أصلًا لتكون Public؟

CI/CD

  • هل Secrets محفوظة في GitHub Secrets؟
  • هل Production لديها Environment خاصة؟
  • هل Required Reviewers موجودون عند الحاجة؟
  • هل يمكن استخدام OIDC بدل Cloud Key طويل العمر؟

Production

  • هل الأسرار داخل Secret Manager؟
  • هل الوصول Least Privilege؟
  • هل Audit Logs تعمل؟
  • هل Rotation ممكنة؟
  • هل يوجد Plan عند التسرب؟

Logs

  • هل تُخفى Tokens؟
  • هل تُخفى Authorization Headers؟
  • هل Connection Strings منزوعة Credentials؟
  • هل لا يتم طباعة process.env؟

٥٥. ما الذي توصي به الشركات الكبرى؟

بعد مقارنة التوصيات الرسمية، يظهر نمط واضح جدًا.

Microsoft

توصي تقريبًا بهذا التسلسل:

Managed Identity
↓
Federated / short-lived credentials
↓
Key Vault when secrets are unavoidable

وتحذر من الاعتماد على Credentials طويلة العمر. (learn.microsoft.com)

Google Cloud

توصي:

AWS

توصي:

GitHub

توصي:

٥٦. مقارنة نهائية

الطريقةالتطوير المحليالإنتاجRotationAuditالصلاحياتالتوصية
Secret داخل الكودسيئخطيرلالالاممنوع
.envممتازضعيفيدويلالاLocal
Environment Variableجيدمقبولغالبًا يدويمحدودمحدودمشاريع بسيطة
GitHub Secretsغير مخصصجيد لـCIيدوينسبيجيدCI/CD
Secret ManagerممكنممتازنعمنعمدقيقProduction
Managed/Workload Identityيعتمدممتاز جدًاتلقائي/قصير العمرنعمدقيقالأفضل عند دعمه

٥٧. كيف أختار في مشروعي؟

إذا كنت تعمل وحدك على تطبيق صغير محلي:

.env.local
+ .gitignore
+ .env.example

قد يكون كافيًا في البداية.

إذا بدأت تنشر Backend:

Hosting Secrets

أفضل من نسخ ملف .env يدويًا إلى السيرفر.

إذا أصبح المشروع Production حقيقيًا:

Secret Manager

أفضل.

وإذا كانت المنصة تسمح:

Managed Identity
Workload Identity
OIDC

فهذا غالبًا الخيار الأكثر نضجًا.

٥٨. لا تنتقل إلى التعقيد دون حاجة

هذا الدرس لا يعني أن كل تطبيق تجريبي يحتاج إلى:

إذا كنت تبني مشروعًا تجريبيًا صغيرًا:

.env.local

مقبول.

لكن اعرف حدوده.

المشكلة ليست استخدام .env.

المشكلة أن تستخدمه ثم تعتقد أنك انتهيت من تصميم الأمان.

٥٩. الخلاصة

إدارة الأسرار ليست سؤالًا بسيطًا من نوع:

أين أضع API Key؟

بل سلسلة قرارات:

هل هذه القيمة Secret أصلًا؟
هل يحتاج التطبيق إليها؟
هل يجب أن تكون في Client؟
هل يمكن استبدالها بهوية؟
من يستطيع الوصول إليها؟
كيف سنغيرها؟
ماذا نفعل إذا تسربت؟
وهل نعرف من قرأها؟

للتطوير المحلي:

.env.local

مع:

.gitignore
.env.example

حل عملي.

للإنتاج:

Secret Manager

أفضل من توزيع ملفات .env.

وللاتصال بين الخدمات الحديثة:

Managed Identity
Workload Identity
OIDC
Temporary Credentials

أفضل غالبًا من Secret طويلة العمر.

والقاعدة الأهم في الدرس كله:

أفضل Secret هو Secret لا تحتاج إلى إنشائه أصلًا.

لا تضع المفتاح داخل الكود.

لا تفترض أن .env خزنة.

لا تضع Secret حقيقية داخل Flutter أو Web Frontend.

لا تستخدم Production credentials في Development.

لا تشارك Credential واحدة بين جميع الخدمات.

لا تطبع الأسرار في Logs.

واستخدم:

Least Privilege + Rotation + Audit + Short-lived identities

كلما استطعت.

فإدارة الأسرار الجيدة لا تعني فقط إخفاء المفتاح.

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

🔗
المصادر الأساسية

اعتمد هذا الدرس على الإرشادات الرسمية لـMicrosoft حول إدارة الأسرار وManaged Identities وZero Trust، وعلى Google Cloud Secret Manager وWorkload Identity Federation، وعلى AWS Secrets Manager وIAM Credentials، وعلى GitHub Actions Secrets وOpenID Connect، إضافة إلى منهج Twelve-Factor App في فصل Config عن Code. (learn.microsoft.com)