من أكثر الأخطاء شيوعًا في مشاريع الفايب كودنق أن يبدأ المطور بكتابة:
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=...
إذا تسربت هذه القيم فقد يستطيع المهاجم:
- استهلاك رصيد API الخاص بك.
- قراءة البيانات أو تعديلها.
- تنفيذ عمليات باسم الخادم.
- الوصول إلى قاعدة البيانات.
- توقيع Tokens.
- أو تجاوز صلاحيات التطبيق.
وتوصي Microsoft بالفصل بين الأسرار والإعدادات العادية، وعدم استخدام خزائن الأسرار لتخزين كل إعداد في النظام بلا حاجة. (learn.microsoft.com)
قاعدة مهمة
ليس كل Config سرًا، لكن كل Secret يحتاج إلى حماية أكثر من مجرد وضعه في ملف إعدادات.
٢. الخطأ الأول: كتابة المفتاح داخل الكود
من أسوأ الطرق:
const stripeSecretKey =
"sk_live_XXXXXXXXXXXXXXXX";
أو:
const openAiKey = 'sk-...';
لماذا؟
لأن السر أصبح جزءًا من:
- Source Code.
- Git History.
- Pull Requests.
- Backups.
- Build artifacts.
- وقد يصل إلى الأشخاص الذين لديهم حق قراءة المستودع.
حتى إذا حذفته بعد ذلك، قد يبقى داخل سجل Git.
لذلك القاعدة الأولى:
لا تكتب الأسرار داخل الكود.
٣. ماذا يحدث إذا رفعت Secret إلى GitHub ثم حذفته؟
لنفترض أنك ارتكبت الخطأ التالي:
commit 1
→ يحتوي API_KEY
ثم لاحظت المشكلة وحذفت السطر:
commit 2
→ لا يحتوي API_KEY
هل انتهت المشكلة؟
لا.
لأن المفتاح قد يبقى في:
Git history
وقد يكون:
- نُسخ.
- فُهرس.
- التقطته أدوات آلية.
- أو شاهده شخص آخر.
عند تسرب Secret، لا تتعامل معه على أنه «مخفي الآن».
تعامل معه على أنه:
Compromised (تم كشفه أو إفشاؤه)
والإجراء الصحيح:
- ألغِ المفتاح القديم.
- أنشئ مفتاحًا جديدًا.
- حدّث الخدمات.
- راقب Logs والاستخدام.
- نظف Git History عند الحاجة.
- أضف 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 قد:
- يُرفع إلى Git بالخطأ.
- يُرسل إلى زميل.
- يُنسخ داخل Backup.
- يظهر في ملف Support.
- يُقرأ من أي شخص لديه وصول إلى الجهاز.
- أو ينتهي داخل Logs بسبب Debug سيئ.
ولهذا تحذر 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.- Docker.
- منصة الاستضافة.
- GitHub Actions.
- Kubernetes.
- Secret Manager Integration.
إذن:
.env مجرد طريقة واحدة لتوفير Environment Variables.
٩. هل Environment Variables آمنة؟
أفضل من Hardcoding.
لكن ليست حماية مطلقة.
قد تتسرب عبر:
- Debug endpoint.
- Crash dump.
- Logging.
- أدوات تشخيص.
- مكتبة تطبع جميع Environment Variables.
Google Cloud تحذر من أن تمرير الأسرار عبر الملفات أو Environment Variables قد يؤدي إلى تسربها بسبب Misconfiguration أو Debugging، وتوصي عند الإمكان باستخدام Secret Manager API مباشرة. (cloud.google.com)
إذن التدرج يصبح:
Hardcoded secret
↓
.env
↓
Environment variable
↓
Secret Manager
لكن ما زال هناك مستوى أفضل سنصل إليه لاحقًا.
١٠. ما هو Secret Manager؟
Secret Manager هو خدمة مخصصة لحفظ وإدارة الأسرار.
من أشهر الأمثلة:
- AWS Secrets Manager.
- Google Secret Manager.
- Azure Key Vault.
- HashiCorp Vault.
بدل وضع:
DATABASE_PASSWORD=supersecret
داخل خادمك، يصبح السر محفوظًا داخل Vault:
prod/database/password
والتطبيق يطلبه عند الحاجة وفق صلاحيات محددة.
١١. ما الذي يضيفه Secret Manager؟
عادةً يوفر مزايا مثل:
- تشفير الأسرار.
- صلاحيات IAM/RBAC.
- Audit Logs.
- Versioning.
- Rotation.
- Expiration.
- Revocation.
- فصل البيئات.
- مراقبة الوصول.
AWS توصي باستخدام Secrets Manager لحفظ Credentials والمعلومات الحساسة، مع تطبيق Rotation وLeast Privilege ومراقبة الوصول. (docs.aws.amazon.com)
وتوصي Azure باستخدام Key Vault للأشياء مثل:
- كلمات المرور.
- Connection Strings.
- API Keys.
- المفاتيح الخاصة. (learn.microsoft.com)
١٢. كيف يعمل Secret Manager؟
التصميم البسيط:
Application
↓
Authenticates using its identity
↓
Secret Manager
↓
Returns allowed secret
بدل:
Application
→ reads password from local .env file
الفرق أن Secret Manager يستطيع معرفة:
- من طلب السر؟
- متى؟
- أي Secret طلب؟
- هل لديه صلاحية؟
- وأي Version حصل عليها؟
وهذا مهم جدًا في الإنتاج.
١٣. هل Secret Manager أفضل من .env دائمًا؟
ليس بالضرورة لكل حالة.
للتطوير المحلي البسيط:
.env.local
قد يكون أسهل وأسرع.
لكن في Production:
Secret Manager
غالبًا أفضل.
لأنك تحصل على إدارة مركزية بدل توزيع أسرار نصية بين:
- الخوادم.
- المطورين.
- CI.
- ملفات إعداد.
لكن Secret Manager يضيف تعقيدًا أيضًا:
- يحتاج IAM.
- يحتاج Integration.
- يحتاج خطة Rotation.
- قد يضيف Network Call.
- ويحتاج Monitoring.
لذلك لا تضف Vault إلى مشروع صغير فقط لأن الكلمة تبدو احترافية.
استخدمه عندما تكون هناك أسرار إنتاج حقيقية تحتاج إدارة.
١٤. مقارنة .env وSecret Manager
| العنصر | .env | Secret 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 لديها الفكرة نفسها عبر:
- IAM Roles.
- Temporary Credentials.
- STS.
- OIDC federation.
الهدف واحد:
لا تستخدم Access Key طويلة العمر إذا كانت الخدمة تستطيع الحصول على Temporary Credentials تلقائيًا.
١٩. إذن ما أفضل ترتيب؟
يمكن التفكير فيه بهذا الشكل:
Hardcoded Secret
↓
.env
↓
Hosting Environment Variable
↓
Secret Manager
↓
Managed / Workload Identity
كلما نزلنا إلى الأسفل:
- نقل اعتماد أقل على أسرار ثابتة.
- Rotation أقل يدويًا.
- Blast Radius أقل.
- إدارة أفضل.
٢٠. أفضل 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
هذا يساعد في:
- التحقيق الأمني.
- اكتشاف السلوك غير المعتاد.
- معرفة Consumer الفعلي.
- مراجعة الصلاحيات.
في ملف .env لا تعرف من قرأه.
٣١. لا تطبع الأسرار في Logs
يمكن أن تستخدم أفضل Secret Manager في العالم ثم تكتب:
console.log(process.env);
وتكشف كل شيء.
أو:
console.log(config);
فتظهر:
DATABASE_PASSWORD=...
OPENAI_API_KEY=...
داخل Logs.
الحل:
- لا تطبع Environment بالكامل.
- طبق Redaction.
- لا تعرض Stack Traces الحساسة للمستخدم.
- لا تسجل Authorization Headers.
- لا تسجل Cookies أو Tokens.
٣٢. لا تمرر السر في Command Line بلا حاجة
مثل:
deploy --password mysecret
قد يظهر السر في:
- Shell History.
- Process List.
- Logs.
الأفضل استخدام الوسيلة التي تدعمها الأداة مثل:
- Environment variable.
- stdin.
- Token provider.
- Secret manager integration.
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 الذي:
- يتحقق من المستخدم.
- يطبق Rate Limit.
- يحدد Tokens.
- يراقب التكلفة.
- ثم يستدعي الخدمة الخارجية.
٣٥. ماذا عن 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_...
الأول مصمم للعميل.
الثاني للخادم فقط.
كذلك بعض الخدمات توفر:
- Public Key.
- Anon Key.
- Publishable Key.
ويكون الأمان الحقيقي معتمدًا على:
- RLS.
- Scopes.
- Domain restrictions.
- Server-side authorization.
لذلك لا تسأل فقط:
هل هذا API Key؟
بل:
هل وثائق المزود تقول إنه Public أم Secret؟
٣٧. مثال مهم: Supabase
قد يحتوي مشروع Supabase على:
anon/public key
ومفتاح:
service role
الفرق بينهما كبير.
الـpublic/anon key مصمم ليكون مستخدمًا في Client ضمن نموذج أمان يعتمد على RLS.
أما:
service role key
فلديه صلاحيات قوية جدًا ولا ينبغي وضعه داخل تطبيق المستخدم.
إذا وضعته في Flutter أو Web:
يجب اعتباره متسربًا.
٣٨. Secret Scanning
لا تعتمد على الانتباه البشري فقط.
استخدم أدوات تبحث عن أنماط الأسرار في الكود.
مثل:
- GitHub Secret Scanning.
- pre-commit hooks.
- CI scanners.
- أدوات SAST المناسبة.
الهدف اكتشاف:
sk_live_...
AWS access key
private key
database password
قبل وصولها إلى Production.
٣٩. ماذا تفعل إذا اكتشف Secret Scanner مفتاحًا؟
لا تقل:
False positive غالبًا.
افحصه.
إذا كان حقيقيًا:
- ألغِ المفتاح.
- أنشئ واحدًا جديدًا.
- ابحث عن مكان استخدامه.
- افحص Git History.
- افحص CI logs.
- افحص Artifact.
- راقب مزود الخدمة للاستخدام الغريب.
٤٠. لا تجعل Secrets تظهر في رسائل الخطأ
مثال سيئ:
Failed to connect to:
postgres://admin:password123@db.example.com
وصل Connection String كاملة إلى:
- Log.
- Sentry.
- Support ticket.
الأفضل:
Database connection failed.
host=db.example.com
credential=[REDACTED]
٤١. هل نخزن Secrets في قاعدة البيانات؟
أحيانًا تحتاج إلى تخزين:
- OAuth refresh token.
- API key لمستخدم أو Tenant.
- Credential لخدمة خارجية.
لا تخزنها Plain Text بلا حماية إذا كانت حساسة.
قد تحتاج إلى:
- Encryption at rest.
- KMS.
- Envelope encryption.
- صلاحيات محدودة.
- Rotation.
وإذا كان النظام لا يحتاج لاسترجاع القيمة الأصلية، لا تخزنها أصلًا.
مثل كلمات المرور:
لا تُشفّر فقط، بل تستخدم 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
فقد تزيد:
- Latency.
- التكلفة.
- الاعتماد على Vault.
يمكن للتطبيق:
- قراءة Secret عند التشغيل.
- الاحتفاظ بها في ذاكرة العملية.
- تحديثها عند 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 للجميع.
الأفضل أن تعطي الشخص:
- حسابًا.
- Role.
- صلاحية حسب الحاجة.
وحين يغادر الفريق:
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
توصي:
- Workload Identity Federation عند الإمكان.
- Secret Manager للأسرار التي لا يمكن الاستغناء عنها.
- Least Privilege.
- فصل البيئات.
- وتجنب الملفات والمتغيرات البيئية عندما يكون الوصول المباشر إلى Secret Manager أكثر أمانًا. (cloud.google.com)
AWS
توصي:
- IAM Roles وTemporary Credentials متى أمكن.
- Secrets Manager للأسرار.
- Rotation.
- Caching.
- Least Privilege.
- Logging ومراقبة الوصول. (docs.aws.amazon.com)
GitHub
توصي:
- بعدم وضع الأسرار في Variables العادية.
- استخدام Secrets.
- استخدام Environments لفصل Production.
- تقليل الصلاحيات.
- والاعتماد على OIDC مع مزودي Cloud بدل تخزين Credentials طويلة العمر عندما يكون ذلك ممكنًا. (docs.github.com)
٥٦. مقارنة نهائية
| الطريقة | التطوير المحلي | الإنتاج | Rotation | Audit | الصلاحيات | التوصية |
|---|---|---|---|---|---|---|
| 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
فهذا غالبًا الخيار الأكثر نضجًا.
٥٨. لا تنتقل إلى التعقيد دون حاجة
هذا الدرس لا يعني أن كل تطبيق تجريبي يحتاج إلى:
- Vault Cluster.
- KMS معقد.
- PKI.
- عشر خدمات هوية.
إذا كنت تبني مشروعًا تجريبيًا صغيرًا:
.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)