تأیید محافظت‌شده Android

برای کمک به شما در تأیید قصد کاربران هنگام شروع تراکنش حساس، مانند پرداخت، دستگاه‌های پشتیبانی‌شده‌ای که Android نسخه ۹ (سطح API‏ ۲۸) یا بالاتر را اجرا می‌کنند به شما امکان می‌دهند از «تأییدیه محافظت‌شده Android» استفاده کنید. هنگام استفاده از این گردش کار، برنامه‌تان پیام‌واره‌ای به کاربر نشان می‌دهد و از او می‌خواهد بیانیه کوتاهی را تأیید کند که قصد او را برای تکمیل تراکنش حساس مجدداً تأیید می‌کند.

اگر کاربر بیانیه را بپذیرد، برنامه‌تان می‌تواند از کلیدی از Android Keystore برای امضای پیام نشان‌داده‌شده در کادر گفتگو استفاده کند. امضا با اطمینان بسیار بالا نشان می‌دهد که کاربر بیانیه را دیده و با آن موافقت کرده است.

احتیاط: «تأییدیه محافظت‌شدهٔ Android» کانال اطلاعاتی ایمنی برای کاربر فراهم نمی‌کند. برنامه شما نمی‌تواند هیچ‌گونه تضمین محرمانگی فراتر از آنچه پلاتفرم Android ارائه می‌دهد فرض کند. به‌ویژه، از این گردش کار برای نمایش اطلاعات حساسی که معمولاً در دستگاه کاربر نشان نمی‌دهید استفاده نکنید.

پس‌از اینکه کاربر پیام را تأیید کرد، یکپارچگی پیام تضمین می‌شود، اما برنامه‌تان همچنان باید از رمزگذاری داده‌های درحال انتقال برای محافظت از محرمانه بودن پیام امضاشده استفاده کند.

برای ارائه پشتیبانی از تأیید کاربر با اطمینان بالا در برنامه‌تان، مراحل زیر را تکمیل کنید:

  1. کلید امضای نامتقارنی بااستفاده از کلاس KeyGenParameterSpec.Builder تولید کنید. هنگام ایجاد کلید، true را به setUserConfirmationRequired() منتقل کنید. همچنین، setAttestationChallenge() را فراخوانی کنید، و مقدار چالش مناسبی را که طرف اعتمادکننده ارائه کرده است ارسال کنید.

  2. کلید جدیداً تولیدشده و گواهی تصدیق کلیدتان را در طرف متکی مناسب ثبت کنید.

  3. جزئیات تراکنش را به سرورتان ارسال کنید و از آن بخواهید یک شیء بزرگ دودویی (BLOB) از داده‌های اضافی تولید کند و برگرداند. داده‌های اضافی ممکن است شامل داده‌های تأییدنشده یا نکات تجزیه باشد، مثل زبان رشته پیام‌واره.

    برای پیاده‌سازی امن‌تر، BLOB باید حاوی یک عدد تصادفی رمزنگاری‌شده باشد تا از حملات بازپخش محافظت کند و ابهام تراکنش‌ها را برطرف کند.

  4. شیء ConfirmationCallback را راه‌اندازی کنید که وقتی کاربر پیام‌واره نشان‌داده‌شده در کادر گفتگوی تأیید را پذیرفت، به برنامه شما اطلاع دهد:

    کاتلین

    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() فراخوانی برگشتی فراخوانده می‌شود. ‫BLOB‏ dataThatWasConfirmed یک ساختار داده CBOR است که در میان جزئیات دیگر، حاوی نوشتار پیام‌واره‌ای است که کاربر دیده است و همچنین داده‌های اضافی که به سازنده ConfirmationPrompt ارسال کرده‌اید. از کلید قبلاً ایجادشده برای امضای dataThatWasConfirmed BLOB استفاده کنید، سپس این BLOB را به‌همراه امضا و جزئیات تراکنش به طرف متکی برگردانید.

    برای استفاده کامل از تضمین امنیتی که «تأییدیه محافظت‌شده Android» ارائه می‌دهد، طرف متکی باید مراحل زیر را پس‌از دریافت پیام امضاشده انجام دهد:

    1. امضای پیام و همچنین زنجیره گواهی تصدیق کلید امضا را بررسی کنید.
    2. بررسی کنید که گواهی تصدیق دارای پرچم TRUSTED_CONFIRMATION_REQUIRED باشد، که نشان می‌دهد کلید امضا به تأیید کاربر مطمئن نیاز دارد. اگر کلید امضا کلید RSA است، بررسی کنید که ویژگی PURPOSE_ENCRYPT یا PURPOSE_DECRYPT را نداشته باشد.
    3. extraData را بررسی کنید تا مطمئن شوید این پیام تأیید متعلق به درخواست جدیدی است و هنوز پردازش نشده است. این مرحله از شما دربرابر حملات بازپخش محافظت می‌کند.
    4. promptText را برای اطلاعات مربوط به کنش یا درخواست تأییدشده تجزیه کنید. به‌یاد داشته باشید که promptText تنها بخشی از پیام است که کاربر واقعاً تأیید کرده است. طرف متکی هرگز نباید فرض کند که داده‌های تأییدشدنی موجود در extraData با promptText مطابقت دارد.
  5. منطقی مشابه آنچه در تکه‌کد زیر نشان داده شده است اضافه کنید تا خود کادر گفتگو نمایش داده شود:

    کاتلین

    // 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»، به منابع زیر مراجعه کنید.

وبلاگ‌ها