ReactNative/security

من موسوعة حسوب
اذهب إلى التنقل اذهب إلى البحث

الأمن Security

d security chart

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

سنتعرف على أفضل الممارسات لتخزين المعلومات الحساسة والاستيثاق authentication وأمان الشبكة والأدوات التي ستساعدك على تأمين تطبيقك.

تخزين المعلومات الحساسة

لا تخزّن أبدًا مفاتيح واجهة برمجة التطبيقات API الحسّاسة في شيفرة تطبيقك، إذ يمكن لأي شخص يتفقد حزمة التطبيق الوصول إلى أي شيء موجود في هذه الشيفرة. تُعَد أدوات مثل react-native-dotenv و react-native-config أدوات رائعة لإضافة متغيرات خاصة بالبيئة مثل نقاط نهاية واجهة برمجة التطبيقات، ولكن لا ينبغي الخلط بينها وبين متغيرات البيئة من جانب الخادم، والتي يمكن أن تحتوي غالبًا على أسرار ومفاتيح API.

إن كان لديك مفتاح API أو سر للوصول إلى بعض الموارد في تطبيقك، فإن الطريقة الأكثر أمانًا للتعامل مع ذلك هي إنشاء طبقة تزامن Orchestration بين تطبيقك والمورد. قد تكون هذه العملية دون خادم (كاستخدام عمليةات AWS Lambda أو Google Cloud) والتي يمكنها تمرير الطلب باستخدام سر أو مفتاح API المطلوب. لا يمكن لمستخدمي API الوصول إلى الأسرار الموجودة في شيفرة جانب الخادم بالطريقة نفسها التي يمكن للأسرار الموجودة في شيفرة تطبيقك الوصول إليها.

اختر النوع المناسب للتخزين بالنسبة لبيانات المستخدم المستمرة بناءً على حساسية هذه البيانات. ستجد غالبًا أثناء استخدام تطبيقك الحاجة إلى حفظ البيانات على الجهاز، سواء لدعم استخدام تطبيقك في وضع عدم الاتصال، أو تقليل طلبات الشبكة أو حفظ رمز وصول المستخدم بين الجلسات منأجل عدم الاضطرار إلى إعادة الاستيثاق في كل مرة يُستخدَم فيها التطبيق.

البيانات المستمر Persisted والبيانات غير المستمرة Unpersisted: تُكتَب البيانات المستمرة على قرص الجهاز الصلب، مما يتيح لتطبيقك قراءة البيانات عبر عمليات تشغيل التطبيق دون الحاجة إلى إجراء طلب شبكة آخر لجلبها أو مطالبة المستخدم بإعادة إدخالها. ولكن هذا أيضًا يمكن أن يجعل تلك البيانات أكثر عرضة لأن يصل إليها المهاجمون. لا تُكتَب البيانات غير المستمرة على القرص الصلب مطلقًا، لذلك لا توجد بيانات للوصول إليها.

التخزين غير المتزامن Async Storage

التخزين غير المتزامن هو وحدة يحتفظ بها المجتمع لإطار عمل React Native والتي توفر مخزنًا غير متزامن وغير مشفر له زوج مفتاح-قيمة key-value. لا تتشارك التطبيقات بالتخزين غير المتزامن، فلكل تطبيق بيئته المعزولة ولا يمكنه الوصول إلى بيانات التطبيقات الأخرى.

حالات استخدم التخزين غير المتزامن حالات عدم استخدام التخزين غير المتزامن
تشغيل استمرار البيانات غير الحساسة عبر التطبيق تخزين الرموز Token storage
حالة Redux المستمرة الأسرار Secrets
حالة GraphQL المستمرة
تخزين المتغيرات العامة على مستوى التطبيق

ملاحظات المطور

في الويب: التخزين غير المتزامن هو مكافئ React Native للتخزين المحلي من الويب.

التخزين الآمن

لا يتضمّن React Native أي طريقة لتخزين البيانات الحساسة، ولكن هناك حلول قائمة مسبقًا لمنصات Android و iOS.

خدمات Keychain (في iOS)

تتيح لك خدمات Keychain تخزين أجزاء صغيرة من معلومات المستخدم الحساسة بأمان، ويُعَد مكانًا مثاليًا لتخزين الشهادات والرموز وكلمات المرور وأي معلومات حساسة أخرى لا تنتمي إلى التخزين غير المتزامن.

التفضيلات المشتركة الآمنة Secure Shared Preferences (في Android)

التفضيلات المشتركة هي مكافئ مخزن بيانات الأزواج قيمة-مفتاح المستمر في Android. لا تُشفَّر البيانات في التفضيلات المشتركة افتراضيًا، ولكن التفضيلات المشتركة المشفَّرة تغلّف تفضيلات نظام Android المشتركة، وتشفّر المفاتيح والقيم تلقائيًا.

Keystore في Android

يتيح لك نظام Android Keystore تخزين مفاتيح التشفير في حاوية ليصعب على الجهاز استخراجها.

يمكنك استخدام خدمات iOS Keychain أو Android Secure Shared Preferences إما من خلال كتابة جسر بنفسك أو استخدام مكتبة تغلّفها لك وتوفر واجهة API موحدة على مسؤوليتك الخاصة. فيما يلي بعض المكتبات التي يمكنك الاطلاع عليها:

  • react-native-sensitive-info الآمنة لنظام iOS، لكنها تستخدم تفضيلات Android المشتركة لنظام Android (وهي غير آمنة افتراضيًا)، ولكن يوجد فرع منها يستخدم Android Keystore.

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

security deep linking

الاستيثاق Authentication والربط العميق Deep Linking

تحتوي تطبيقات الهواتف المحمولة على ثغرة أمنية فريدة غير موجودة على الويب، وهذه الثغرة هي الربط العميق deep linking، والذي هو طريقة لإرسال البيانات مباشرة إلى تطبيق أصيل من مصدر خارجي. يشبه الرابط العميق الشكل app://‎ حيث app هو مخطط تطبيقك وأي شيء يتبع الرمز // يمكن استخدامه داخليًا لمعالجة الطلب.

إن أردت بناء تطبيق لمتجر الكتروني على سبيل المثال، فيمكنك استخدام الرابط app://products/1 للربط العميق بتطبيقك وفتح صفحة تفاصيل المنتج لمنتج له المعرّف 1، حيث يشبه ذلك عناوين URL على الويب، ولكن مع اختلاف واحد مهم، وهو أن الروابط العميقة ليست آمنة ولا يجب عليك أبدًا إرسال أي معلومات حساسة فيها.

يرجع سبب عدم أمان الروابط العميقة إلى عدم وجود طريقة مركزية لتسجيل مخططات عناوين URL، ولكن بصفتك مطور تطبيقات، فيمكنك استخدام أي مخطط URL تقريبًا تختاره عن طريق إعداده في Xcode على نظام iOS أو إضافة نيّة فعل intent على نظام Android.

لا يوجد ما يمنع أي تطبيق ضار من سرقة رابطك العميق عن طريق التسجيل أيضًا في نفس المخطط ثم الحصول على حق الوصول إلى البيانات التي يحتوي عليها رابطك. ليس إرسال شيء كالرابط app://products/1 ضارًا، لكن يُعَد إرسال رموز مصدر قلق أمني.

إذا احتوى نظام التشغيل على تطبيقين أو أكثر للاختيار من بينها عند فتح رابط، فسيعرض نظام Android للمستخدم نافذة modal ويطلب منه اختيار التطبيق الذي سيستخدمه لفتح الرابط. لكن يختار نظام التشغيل iOS عنك في هذه الحالة، لذلك لن يكون المستخدم على دراية بذلك. اتخذت شركة Apple خطوات لمعالجة هذه المشكلة في إصدارات iOS الأحدث (iOS 11) حيث أسست مبدأ من يأتي أولًا يُخدَّم أولًا، على الرغم من أنه لا يزال من الممكن استغلال هذه الثغرة الأمنية بطرق مختلفة. سيسمح استخدام الروابط العامة universal links بالربط بالمحتوى داخل تطبيقك في نظام iOS بأمان.

OAuth2 وعمليات إعادة التوجيه Redirects

يحظى بروتوكول الاستيثاق OAuth2 بشعبية كبيرة في الوقت الحاضر، ويفتخر بأنه البروتوكول الأكثر اكتمالاً وأمانًا، ويعتمد بروتوكول OpenID Connect أيضًا عليه. يُطلَب من المستخدم في بروتوكول OAuth2 الاستيثاق عبر طرف ثالث، وإن نجح الاستيثاق، فسيعيد هذا الطرف الثالث التوجيه إلى التطبيق الطالب برمز تحقّق يمكن استبداله برمز JSON Web Token أو اختصارًا JWT، والذي هو معيار مفتوح لنقل المعلومات الآمن بين الأطراف على الويب.

تُعَد خطوة إعادة التوجيه هذه آمنة على الويب، لأن عناوين URL على الويب مضمونة أنها فريدة. لكن هذا ليس صحيحًا بالنسبة للتطبيقات، لأنه لا توجد طريقة مركزية لتسجيل مخططات عناوين URL، لذلك يجب إضافة فحص إضافي على شكل PKCE من أجل معالجة هذا القلق الأمني.

يرمز PKCE -الذي يُنطق "Pixy"- إلى Proof of Key Code Exchange إثبات تبادل شيفرة المفتاح، وهو توسّع لمواصفات بروتوكول OAuth 2. يتضمن PKCE إضافة طبقة أمان إضافية تتحقق من أن طلبات الاستيثاق وتبادل الرموز آتية من نفس العميل. يستخدم PKCE خوارزمية التشفير المختصَرة SHA 256، حيث تنشئ خوارزمية SHA 256 "توقيعًا" فريدًا لنص أو ملف من أي حجم، ولكنه هذا التوقيع:

  • دائمًا له نفس الطول بغض النظر عن ملف الإدخال.
  • مضمون لإعطاء نفس النتيجة دائمًا لنفس الدخل.
  • باتجاه واحد (أي لا يمكنك عكس إعداده للكشف عن الدخل الأصلي).

لديك الآن قيمتان:

  • code_verifier: سلسلة عشوائية كبيرة ينشئها العميل.
  • code_challenge: قيمة SHA 256 الخاصة بالسلسلة code_verifier.

يرسل العميل code_challenge أثناء طلب ‎/authorize الأولي إلى code_verifier التي يحتفظ بها في الذاكرة. يرسل العميل أيضًا code_verifier التي اُستخدِمت لإنشاء code_challenge بعد إعادة طلب الترخيص authorize بصورة صحيحة. سيحسب IDP بعد ذلك قيمة code_challenge ويتأكد من تطابقها مع القيمة التي أُعِدت في طلب ‎/authorize الأول، ويرسل رمز الوصول إن كانت القيم متطابقة فقط.

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

المكتبة التي يجب مراعاتها في بروتوكول OAuth الأصيل هي react-native-app-auth، والتي هي عبارة عن SDK للتواصل مع مزوّدي بروتوكول OAuth2، وتغلّف مكتبات AppAuth-iOS و AppAuth-Android الأصيلة ويمكنها دعم PKCE.

يمكن للمكتبة React-native-app-auth أن تدعم PKCE فقط إذا كان مزوّد الهويات Identity Provider الخاص بك يدعمها.

diagram pkce

أمن الشبكة

يجب أن تستخدم واجهات API الخاصة بك دائمًا تشفير SSL. يحمي تشفير SSL من قراءة البيانات المطلوبة كنص صرف بين وقت مغادرتها الخادم وقبل وصولها إلى العميل، حيث يمكنك معرفة أن نقطة النهاية آمنة، لأنها تبدأ بـ https://‎ عوضًا عن http://‎.

تثبيت SSL