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

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

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

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

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

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

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

  2. سجِّل المفتاح الذي تم إنشاؤه حديثًا وشهادة المصادقة الخاصة به لدى الجهة المعتمِدة المناسبة.

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

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

  4. يمكنك إعداد عنصر ConfirmationCallback الذي يُعلم تطبيقك عندما يقبل المستخدم الطلب المعروض في مربّع حوار التأكيد:

    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 تحتوي، من بين تفاصيل أخرى، على نص الطلب الذي رآه المستخدم بالإضافة إلى البيانات الإضافية التي تم تمريرها إلى أداة إنشاء ConfirmationPrompt. استخدِم المفتاح الذي تم إنشاؤه سابقًا لتوقيع ملف BLOB الخاص بـ "dataThatWasConfirmed"، ثم أرسِل ملف BLOB هذا، إلى جانب التوقيع وتفاصيل المعاملة، إلى الجهة المعتمدة.

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

    1. تحقَّق من التوقيع على الرسالة بالإضافة إلى سلسلة شهادات المصادقة لمفتاح التوقيع.
    2. تأكَّد من ضبط علامة TRUSTED_CONFIRMATION_REQUIRED في شهادة المصادقة، ما يشير إلى أنّ مفتاح التوقيع يتطلّب تأكيدًا من مستخدم موثوق به. إذا كان مفتاح التوقيع هو مفتاح RSA، يُرجى التأكّد من أنّه لا يتضمّن السمة PURPOSE_ENCRYPT أو PURPOSE_DECRYPT.
    3. يُرجى التحقّق من extraData للتأكّد من أنّ رسالة التأكيد هذه تخصّ طلبًا جديدًا لم تتم معالجته بعد. تحمي هذه الخطوة من هجمات إعادة الإرسال.
    4. تحليل promptText للحصول على معلومات حول الإجراء أو الطلب المؤكَّد يُرجى العِلم أنّ promptText هو الجزء الوحيد من الرسالة الذي أكّده المستخدم فعليًا. يجب ألا تفترض الجهة المعتمدة مطلقًا أنّ البيانات التي سيتم تأكيدها والمضمّنة في 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"، يُرجى الاطّلاع على المراجع التالية.

المدوّنات