متابعة حول كيفية تخزين الرموز بشكل آمن في Android

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

الأمن المطلق غير موجود. الأمن عبارة عن مجموعة من التدابير ، يتم تجميعها وتجميعها ، في محاولة لإبطاء ما لا مفر منه.

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

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

يستخدم التدبير الأول المطلق الذي سيتم تطبيقه اتصال SSL (طبقة مآخذ التوصيل الآمنة) بين العميل والخادم. انتقل مرة أخرى إلى الاقتباس الأولي. هذا لا يضمن الخصوصية المطلقة والأمن ، على الرغم من أنه يجعل وظيفة أولية جيدة.

عندما تستخدم اتصال SSL (مثل عندما ترى الخزانة في متصفحك) فهذا يشير إلى أن الاتصال بينك وبين الخادم مشفر. على المستوى النظري ، لا شيء يستطيع الوصول إلى المعلومات الواردة في هذه الطلبات (*)

(*) هل ذكرت أن الأمن المطلق غير موجود؟ لا يزال يمكن اختراق اتصالات طبقة المقابس الآمنة. لا تنوي هذه المقالة تقديم قائمة شاملة بجميع الهجمات المحتملة ، لكنني أريد أن أخبركم ببعض الاحتمالات. يمكن استخدام شهادات SSL المزيفة ، بالإضافة إلى هجمات Man-in-the-Middle.

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

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

دعونا نبني قلعتنا من الأرض. في تطبيقنا ، من المحتمل أن نضيف متغيرًا يُسمى API_KEY يتم حقنه تلقائيًا في كل طلب (إذا كنت تستخدم Android ، وربما في عميل التحديثية).

سلسلة نهائية خاصة ثابتة API_KEY = "67a5af7f89ah3katf7m20fdj202"

هذا شيء رائع ، ويعمل إذا أردنا مصادقة عملائنا. المشكلة هي أنه لا يوفر طبقة فعالة للغاية في حد ذاته.

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

سلسلة const v1 ، "67a5af7f89ah3katf7m20fdj202"

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

هل بإمكان Proguard مساعدتنا في تأمين هذه السلسلة ، لذلك لا داعي للقلق بشأنها؟ ليس صحيحا. ينص Proguard في الأسئلة الشائعة الخاصة به على أن تشفير السلسلة غير ممكن تمامًا.

ماذا عن حفظ هذه السلسلة في واحدة من الآليات الأخرى التي يوفرها Android ، مثل SharedPreferences؟ هذه بالكاد فكرة جيدة. يمكن الوصول إلى SharedPreferences بسهولة من Emulator أو أي جهاز جذر. منذ بضع سنوات ، أثبت رجل يدعى سرينيفاس كيف يمكن تغيير النتيجة في لعبة فيديو. نحن نفاد الخيارات هنا!

مجموعة التنمية المحلية (NDK)

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

لا شيء يتوهم هنا. ستتخذ هاتان الوظيفتان قيمة أساسية وسلسلة لتشفيرها أو فك تشفيرها. سيعودون الرمز المميز المشفر أو المشفر ، على التوالي. سوف نسمي الوظيفة التالية كما يلي:

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

هل تستطيع؟

اعطِها لبضع ثوانٍ أخرى إذا لم تكن قد حظيت بها بعد.

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

دعنا نستخدم الآن NDK ، ونواصل تكرار آلية الأمان الخاصة بنا.

يسمح لنا NDK بالوصول إلى قاعدة كود C ++ من كود Android الخاص بنا. كطريقة أولى ، دعنا نأخذ دقيقة للتفكير فيما يجب فعله. قد يكون لدينا وظيفة C ++ أصلية تخزن مفتاح API أو أي بيانات حساسة نحاول تخزينها. يمكن استدعاء هذه الوظيفة لاحقًا من الرمز ، ولن يتم تخزين أي سلسلة في أي ملف Java. هذا من شأنه أن يوفر حماية تلقائية ضد تقنيات decompiling.

تبدو وظيفة C ++ كما يلي:

سيتم استدعاؤها بسهولة في كود جافا الخاص بك:

وسيتم استدعاء وظيفة التشفير / فك التشفير كما في المقتطف التالي:

إذا علمنا إنشاء ملف APK ، أو تعتيمه ، أو إلغاء ترجمته ، ومحاولة الوصول إلى السلسلة الموجودة في الوظيفة الأصلية getSecretKey () ، فلن نتمكن من العثور عليها! فوز؟

ليس صحيحا. يمكن بالفعل تفكيك رمز NDK وتفتيشه. هذا يزداد صعوبة ، وبدأت تتطلب أدوات وتقنيات أكثر تطوراً. لقد تخلصت من 95٪ من أطفال البرنامج النصي ، لكن الفريق الذي لديه ما يكفي من الموارد والدافع سيظل قادرًا على الوصول إلى الرمز المميز. تذكر هذه الجملة؟

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

تقوم Hex Rays ، على سبيل المثال ، بعمل جيد للغاية في إلغاء ترجمة الملفات الأصلية. أنا متأكد من أن هناك مجموعة من الأدوات التي يمكن أن تفكك أي رمز أصلي تم إنشاؤه بواسطة Android (أنا لست مرتبطًا بأشعة Hex ولا أتلقى أي تعويض مالي منها).

إذن ما الحل الذي يمكن أن نستخدمه للتواصل بين الواجهة الخلفية والعميل دون وضع علامة؟

قم بإنشاء المفتاح في الوقت الفعلي على الجهاز.

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

  1. يعرف العميل دالة () تقوم بإرجاع مفتاح.
  2. تعرف الواجهة الخلفية الوظيفة () المنفذة في العميل
  3. يقوم العميل بإنشاء مفتاح من خلال الوظيفة () ، ويتم تسليم هذا إلى الخادم.
  4. يقوم الخادم بالتحقق من ذلك ، ويستمر في الطلب.

هل تربط النقاط؟ بدلاً من الحصول على دالة أصلية تُرجع إليك سلسلة (يمكن التعرف عليها بسهولة) ، فلماذا لا توجد وظيفة تُرجع لك مجموع ثلاثة أعداد أولية عشوائية تتراوح بين 1 و 100؟ أو وظيفة تستغرق اليوم الحالي معبراً عنها في وقت واحد وتضيف 1 إلى كل رقم مختلف؟ ماذا عن أخذ بعض المعلومات السياقية من الجهاز ، مثل مقدار الذاكرة المستخدمة ، لتوفير درجة أعلى من الانتروبيا؟

تتضمن الفقرة الأخيرة سلسلة من الأفكار ، ولكن نأمل أن يكون القارئ الافتراضي لدينا هو النقطة الرئيسية.

ملخص

  1. الأمن المطلق غير موجود.
  2. الجمع بين مجموعة من تدابير الحماية هو المفتاح لتحقيق درجة عالية من الأمن.
  3. لا تقم بتخزين السلسلة الحرفية في التعليمات البرمجية الخاصة بك.
  4. استخدم NDK لإنشاء مفتاح يتم إنشاؤه ذاتيًا.

تذكر الجملة الأولى؟

الأمن المطلق غير موجود. الأمن عبارة عن مجموعة من التدابير ، يتم تجميعها وتجميعها ، في محاولة لإبطاء ما لا مفر منه.

أريد أن أشير مرة أخرى إلى أن هدفك هو حماية أكبر قدر ممكن من التعليمات البرمجية الخاصة بك ، دون أن تفقد منظور أن 100 ٪ من الأمن لا يمكن تحقيقه. ولكن إذا كنت قادرًا على حماية الكود الخاص بك بطريقة تتطلب قدراً هائلاً من الموارد لفك تشفير أي معلومات معقولة لديك ، فستكون قادرًا على النوم بهدوء.

إخلاء صغير

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

ترميز سعيد!

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