لماذا يحتاج خط أنابيب تطبيق الهاتف المحمول إلى التوقيع (وكيفية الحفاظ على أمانه)
لقد انتهيت للتو من بناء تطبيق Android أو iOS. البناء ناجح، والاختبارات اجتازت، وأنت مستعد للإصدار. ولكن قبل أن يتمكن ملف APK أو IPA من الوصول إلى جهاز أي شخص، هناك خطوة أخرى غالبًا ما تبدو وكأنها عبء بيروقراطي: توقيع التطبيق.
قد يكون من المغري التعامل مع التوقيع كعنصر اختياري في قائمة المهام. ولكن إذا سبق لك أن فقدت ملف keystore، أو شاهدت شهادة تنتهي صلاحيتها في ليلة الجمعة، أو قمت بطريق الخطأ بإدراج ملف تعريف توفير (provisioning profile) في مستودع عام، فأنت تعلم أن الأمور تصبح جدية هنا. التوقيع ليس مجرد إجراء شكلي تقني. إنه طبقة الأمان التي تثبت أن تطبيقك جاء منك، وليس من شخص أعاد تعبئته أو انتحل هويتك.
ما الذي يفعله التوقيع فعليًا
عندما توقع تطبيقًا، فإنك تُرفق توقيعًا رقميًا يربط الملف الثنائي بهويتك. يتم التحقق من هذا التوقيع بواسطة نظام التشغيل ومتجر التطبيقات. إذا لم يتطابق التوقيع، فلن يتم تثبيت التطبيق، أو سيرفض المتجر التحميل.
بالنسبة لنظام Android، يستخدم التوقيع ملف keystore. يحتوي هذا الملف على مفتاح خاص وشهادة رقمية. اعتبره كختمك الرسمي. في كل مرة تقوم فيها ببناء ملف APK أو AAB للإصدار، تقوم بختمه بملف keystore هذا. إذا استخدمت ملف keystore مختلفًا لاحقًا، سيتعامل Android مع التطبيق كتطبيق مختلف تمامًا، حتى لو كان اسم الحزمة متطابقًا. وهذا يعني أن المستخدمين لا يمكنهم تحديث التطبيق فوق التثبيت الحالي. سيتعين عليهم إلغاء تثبيت الإصدار القديم أولاً، مما يؤدي إلى فقدان جميع البيانات المحلية.
بالنسبة لنظام iOS، تكون العملية أكثر تعقيدًا. أنت بحاجة إلى شيئين: شهادة وملف تعريف توفير (provisioning profile). الشهادة هي هويتك الرقمية كمطور. يربط ملف تعريف التوفير بين الشهادة ومعرف التطبيق (App ID) وقائمة الأجهزة المسموح لها بتشغيل التطبيق. لتوزيع التطبيق عبر متجر التطبيقات، تستخدم شهادة توزيع وملف تعريف توفير لمتجر التطبيقات. للاختبار الداخلي أو التطوير، تستخدم شهادة تطوير وملف تعريف توفير مخصص (ad-hoc).
المشكلة الحقيقية: الحفاظ على الأسرار في خط الأنابيب
بمجرد أن تفهم ما يتطلبه التوقيع، يصبح السؤال التالي واضحًا: كيف تخزن بيانات الاعتماد هذه في خط أنابيب CI/CD الخاص بك دون كتابتها في الكود الخاص بك أو ملفات التكوين؟
الإجابة هي إدارة الأسرار. ولكن دعنا نكون واضحين بشأن ما لا يجب فعله أولاً.
لا تقم أبدًا بتخزين ملفات keystore أو الشهادات أو ملفات تعريف التوفير في مستودع Git الخاص بك. هذه الملفات هي أسرار، وليست تكوينًا. إذا انتهى بها المطاف في مستودع عام، يمكن لأي شخص توقيع تطبيقات متظاهرًا بأنه أنت. إذا انتهى بها المطاف في مستودع خاص، فلا تزال لديك مشكلة: كل مطور لديه حق الوصول إلى المستودع يمتلك الآن مفاتيح التوقيع الخاصة بالإنتاج. هذا يشكل خطرًا أمنيًا وتدقيقيًا.
بدلاً من ذلك، استخدم مخزن الأسرار الذي توفره منصة CI/CD الخاصة بك. تحتوي GitHub Actions و GitLab CI و Jenkins ومعظم المنصات الأخرى على متغيرات أسرار مدمجة. يمكنك تحميل ملف keystore أو الشهادة الخاص بك كسلسلة مشفرة بـ base64، وتخزينها كمتغير سري، وفك تشفيرها مرة أخرى إلى ملف أثناء تشغيل خط الأنابيب. لا يتم كتابة السر أبدًا على قرص جهاز البناء حتى وقت التشغيل، ولا يظهر أبدًا في السجلات.
إليك مثال ملموس لنظام Android مع GitHub Actions:
- name: Decode keystore
run: echo "${{ secrets.KEYSTORE_BASE64 }}" | base64 --decode > app/release.keystore
لنظام iOS مع Fastlane و GitLab CI:
- name: Decode certificate
run: echo $MATCH_PASSWORD | fastlane match import --git_url $MATCH_REPO
إذا كان فريقك بحاجة إلى مزيد من التحكم، ففكر في استخدام مدير أسرار مخصص مثل AWS Secrets Manager أو Azure Key Vault أو HashiCorp Vault. يقوم خط الأنابيب الخاص بك بجلب بيانات الاعتماد في وقت التشغيل من هذه الخدمات. يمنحك هذا النهج سجلات تدقيق وتحكم في الوصول وتدوير مركزي. لا توجد بيانات الاعتماد داخل تكوين خط الأنابيب نفسه.
إليك نص برمجي كامل بلغة Bash يقوم بجلب ملف keystore من AWS Secrets Manager، وتوقيع ملف APK باستخدام jarsigner، والتحقق من التوقيع:
#!/bin/bash
set -euo pipefail
# Fetch keystore from AWS Secrets Manager
KEYSTORE_SECRET=$(aws secretsmanager get-secret-value \
--secret-id "mobile-app/keystore" \
--query SecretString --output text)
echo "$KEYSTORE_SECRET" | base64 --decode > /tmp/release.keystore
# Sign the APK
jarsigner -verbose -sigalg SHA256withRSA \
-digestalg SHA-256 \
-keystore /tmp/release.keystore \
-storepass "$STORE_PASSWORD" \
app-release-unsigned.apk \
mykeyalias
# Verify the signature
jarsigner -verify -verbose -certs app-release-unsigned.apk
# Clean up
rm -f /tmp/release.keystore
يضمن هذا النص البرمجي عدم تخزين ملف keystore في المستودع أبدًا، ويتم جلبه بشكل آمن في وقت التشغيل، ويتم تنظيفه فورًا بعد التوقيع.
انتهاء صلاحية الشهادة: القاتل الصامت لخط الأنابيب
إليك سيناريو يحدث أكثر مما ينبغي. يعمل خط الأنابيب الخاص بك بشكل جيد لأشهر. ثم في يوم من الأيام، يفشل بناء الإصدار. تتعمق في السجلات وتجد أن شهادة التوقيع قد انتهت صلاحيتها. التطبيق الموجود بالفعل في المتجر لا يزال يعمل بشكل جيد على أجهزة المستخدمين. لكن لا يمكنك تحميل إصدار جديد. يرفض المتجر ذلك لأن التوقيع على الملف الثنائي الجديد غير صالح.
ملفات keystore لنظام Android وشهادات iOS لها تواريخ انتهاء صلاحية. لا يتم تجديدها تلقائيًا. يجب أن يكتشف خط الأنابيب الخاص بك حالات انتهاء الصلاحية الوشيكة وينبه الفريق قبل أن تصبح بيانات الاعتماد غير قابلة للاستخدام. يمكن لنص برمجي بسيط يتحقق من تاريخ صلاحية ملف keystore أو الشهادة ويرسل إشعارًا إلى قناة الدردشة الخاصة بفريقك أن ينقذك من إصدار محظور.
بالنسبة لنظام Android، يمكنك التحقق من انتهاء صلاحية keystore باستخدام:
keytool -list -v -keystore release.keystore -storepass $STORE_PASSWORD | grep "Valid until"
بالنسبة لنظام iOS، تتضمن أداة match الخاصة بـ Fastlane وضع --readonly الذي يظهر تاريخ انتهاء صلاحية الشهادة. يمكنك أيضًا استخدام الأمر security على نظام macOS:
security find-identity -v -p codesigning | grep "iPhone Distribution"
قائمة مراجعة عملية للتوقيع في خط الأنابيب الخاص بك
إذا كنت تقوم بإعداد التوقيع لأول مرة أو تراجع الإعداد الحالي، فاتبع قائمة المراجعة هذه:
- هل يتم تخزين ملفات keystore والشهادات وملفات تعريف التوفير خارج Git؟
- هل يتم تخزين بيانات اعتماد التوقيع في مخزن أسرار منصة CI/CD أو في مدير أسرار خارجي؟
- هل يتم تخزين ملف keystore أو الشهادة المشفر بـ base64 كمتغير سري، وليس في ملف تكوين؟
- هل يقوم خط الأنابيب بفك تشفير السر فقط في وقت التشغيل، في دليل مؤقت؟
- هل يتم تنظيف ملفات التوقيع المؤقتة بعد اكتمال البناء؟
- هل يتحقق خط الأنابيب من انتهاء صلاحية الشهادة وينبه الفريق قبل انتهاء صلاحية بيانات الاعتماد؟
- هل هناك عملية موثقة لتدوير أو تجديد بيانات اعتماد التوقيع؟
- هل تقتصر بيانات اعتماد توقيع الإنتاج على مجموعة صغيرة من أعضاء الفريق الموثوق بهم؟
التوقيع ليس النهاية
بمجرد توقيع تطبيقك، يكون الأرتيفكت جاهزًا للاختبار. لكن الملف الثنائي الموقع الموجود على جهاز البناء ليس هو نفسه الإصدار المختبر. لا يمكن التحقق من تطبيقات الهاتف المحمول بشكل كامل من خلال قراءة الكود أو تشغيل اختبارات الوحدة وحدها. تحتاج إلى تشغيل التطبيق الموقع على أجهزة المحاكاة (emulators/simulators) أو الأجهزة الحقيقية لالتقاط المشكلات التي تظهر فقط في وقت التشغيل.
خطوة التوقيع هي بوابة. إنها تضمن أن ما أنت على وشك اختباره وشحنه هو ملكك حقًا. تعامل معها بنفس العناية التي تعامل بها بيانات اعتماد قاعدة بيانات الإنتاج الخاصة بك. لأنه في كثير من النواحي، هي أكثر قيمة: فقدان كلمة مرور قاعدة البيانات يعني الاستعادة من النسخة الاحتياطية. فقدان ملف keystore الخاص بك يعني فقدان القدرة على تحديث تطبيقك بالكامل.