تأكيد آمن لعمليات المُستخدِم على Android

لمساعدتك في تأكيد نوايا المستخدمين عند بدء معاملة حساسة، مثل إجراء عملية دفع، تتيح لك الأجهزة المتوافقة التي تعمل بالإصدار 9 من نظام التشغيل Android (المستوى 28 من واجهة برمجة التطبيقات) أو الإصدارات الأحدث استخدام ميزة "التأكيد المحمي" من Android. عند استخدام سير العمل هذا، يعرض تطبيقك طلبًا للمستخدم، يطلب منه الموافقة على بيان قصير يؤكِّد رغبته في إكمال المعاملة الحساسة.

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

تنبيه: لا توفّر ميزة "التأكيد الآمن" من Android قناة معلومات آمنة للمستخدم. لا يمكن لتطبيقك تقديم أي ضمانات سرية تتجاوز تلك التي يوفّرها نظام Android الأساسي. على سبيل المثال، لا تستخدِم سير العمل هذا لعرض معلومات حسّاسة لن تعرضها عادةً على جهاز المستخدم.

بعد تأكيد المستخدم للرسالة، يتم ضمان سلامتها، ولكن يجب أن يستخدم تطبيقك ميزة تشفير البيانات أثناء النقل لحماية سرية الرسالة الموقَّعة.

لتقديم تأكيد عالي الأمان للمستخدم في تطبيقك، أكمِل الخطوات التالية:

  1. أنشئ مفتاح توقيع غير متماثل باستخدام فئة KeyGenParameterSpec.Builder. عند إنشاء المفتاح، مرِّر true إلى setUserConfirmationRequired(). اتصل أيضًا بـ setAttestationChallenge()، مع ضبط قيمة طلب مناسبة يوفّرها الطرف الموثوق به.

  2. سجِّل المفتاح الذي تم إنشاؤه حديثًا وشهادة إثبات ملكية المفتاح مع الطرف المعنيّ بالاعتماد.

  3. أرسِل تفاصيل المعاملة إلى خادمك واطلب منه إنشاء ملف ملف ثنائي كبير (BLOB) من البيانات الإضافية وإعادته. قد تتضمن البيانات الإضافية البيانات المطلوب تأكيدها أو تلميحات التحليل، مثل لغة سلسلة المطالبة.

    لإجراء تنفيذ أكثر أمانًا، يجب أن تحتوي كائن تخزين البيانات الثنائية الكبيرة على أمر تشفيري للحماية من هجمات إعادة التشغيل وللتمييز بين المعاملات.

  4. يمكنك إعداد العنصر ConfirmationCallback الذي يُعلم تطبيقك عندما يقبل المستخدم الطلب المعروض في مربع diálogo de confirmación:

    Kotlin

    class MyConfirmationCallback : ConfirmationCallback() {
    
          override fun onConfirmed(dataThatWasConfirmed: ByteArray?) {
              super.onConfirmed(dataThatWasConfirmed)
              // Sign dataThatWasConfirmed using your generated signing key.
              // By completing this process, you generate a signed statement.
          }
    
          override fun onDismissed() {
              super.onDismissed()
              // Handle case where user declined the prompt in the
              // confirmation dialog.
          }
    
          override fun onCanceled() {
              super.onCanceled()
              // Handle case where your app closed the dialog before the user
              // responded to the prompt.
          }
    
          override fun onError(e: Exception?) {
              super.onError(e)
              // Handle the exception that the callback captured.
          }
      }

    Java

    public class MyConfirmationCallback extends ConfirmationCallback {
    
      @Override
      public void onConfirmed(@NonNull byte[] dataThatWasConfirmed) {
          super.onConfirmed(dataThatWasConfirmed);
          // Sign dataThatWasConfirmed using your generated signing key.
          // By completing this process, you generate a signed statement.
      }
    
      @Override
      public void onDismissed() {
          super.onDismissed();
          // Handle case where user declined the prompt in the
          // confirmation dialog.
      }
    
      @Override
      public void onCanceled() {
          super.onCanceled();
          // Handle case where your app closed the dialog before the user
          // responded to the prompt.
      }
    
      @Override
      public void onError(Throwable e) {
          super.onError(e);
          // Handle the exception that the callback captured.
      }
    }

    إذا وافق المستخدم على مربّع الحوار، سيتم استدعاء طريقة معاودة الاتصال onConfirmed(). dataThatWasConfirmed BLOB هي بنية بيانات CBOR تحتوي، من بين التفاصيل الأخرى، على نص الطلب الذي رآه المستخدم بالإضافة إلى data الإضافية التي تم تمريرها إلى ConfirmationPrompt أداة الإنشاء. استخدِم المفتاح الذي تم إنشاؤه سابقًا للتوقيع على dataThatWasConfirmed BLOB، ثم مرِّر كائن تخزين البيانات الكبير هذا مع التوقيع وتفاصيل المعاملة، مرة أخرى إلى الطرف المعتمد.

    للاستفادة الكاملة من الضمان الأمني الذي تقدّمه خدمة "التأكيد الآمن من Android"، على الطرف المُعتمد تنفيذ الخطوات التالية عند استلام رسالة موقَّعة:

    1. تحقَّق من التوقيع على الرسالة بالإضافة إلى سلسلة شهادات التحقّق لمفتاح التوقيع.
    2. تأكَّد من أنّ شهادة الإقرار قد تم ضبط علامة TRUSTED_CONFIRMATION_REQUIRED فيها، ما يشير إلى أنّ مفتاح التوقيع يتطلب تأكيد مستخدم موثوق. إذا كان مفتاح التوقيع هو مفتاح RSA، تأكَّد من أنّه لا يتضمّن السمة PURPOSE_ENCRYPT أو PURPOSE_DECRYPT.
    3. ضَع علامة في المربّع extraData للتأكّد من أنّ رسالة التأكيد هذه تخصّ طلبًا جديدًا لم تتم معالجته بعد. تحمي هذه الخطوة من هجمات تسجيل الجلسات.
    4. يمكنك تحليل promptText للحصول على معلومات حول الإجراء أو الطلب الذي تم تأكيده. تذكَّر أنّ promptText هو الجزء الوحيد من الرسالة الذي confirmed المستخدم فعليًا. يجب ألا يفترض الطرف المُعتمِد أبدًا أنّ البيانات التي يجب تأكيدها والمضمّنة في extraData تتطابق مع promptText.
  5. أضِف منطقًا مشابهًا لما هو موضّح في المقتطف التالي من التعليمات البرمجية لعرض المربّع الحواري نفسه:

    Kotlin

    // This data structure varies by app type. This is an example.
      data class ConfirmationPromptData(val sender: String,
              val receiver: String, val amount: String)
    
      val myExtraData: ByteArray = byteArrayOf()
      val myDialogData = ConfirmationPromptData("Ashlyn", "Jordan", "$500")
      val threadReceivingCallback = Executor { runnable -> runnable.run() }
      val callback = MyConfirmationCallback()
    
      val dialog = ConfirmationPrompt.Builder(context)
              .setPromptText("${myDialogData.sender}, send
                              ${myDialogData.amount} to
                              ${myDialogData.receiver}?")
              .setExtraData(myExtraData)
              .build()
      dialog.presentPrompt(threadReceivingCallback, callback)

    Java

      // This data structure varies by app type. This is an example.
      class ConfirmationPromptData {
          String sender, receiver, amount;
          ConfirmationPromptData(String sender, String receiver, String amount) {
              this.sender = sender;
              this.receiver = receiver;
              this.amount = amount;
          }
      };
      final int MY_EXTRA_DATA_LENGTH = 100;
      byte[] myExtraData = new byte[MY_EXTRA_DATA_LENGTH];
      ConfirmationPromptData myDialogData = new ConfirmationPromptData("Ashlyn", "Jordan", "$500");
      Executor threadReceivingCallback = Runnable::run;
      MyConfirmationCallback callback = new MyConfirmationCallback();
      ConfirmationPrompt dialog = (new ConfirmationPrompt.Builder(getApplicationContext()))
              .setPromptText("${myDialogData.sender}, send ${myDialogData.amount} to ${myDialogData.receiver}?")
              .setExtraData(myExtraData)
              .build();
      dialog.presentPrompt(threadReceivingCallback, callback);

مصادر إضافية

لمزيد من المعلومات عن ميزة "التأكيد المحمي" في Android، يُرجى الرجوع إلى المراجع التالية:

المدوّنات