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

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

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

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

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

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

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

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

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

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

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

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

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

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

    KotlinJava
    // 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)
      // 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، يُرجى الرجوع إلى المراجع التالية:

المدوّنات