Konfirmasi Dilindungi oleh Android

Untuk membantu Anda mengonfirmasi niat pengguna saat mereka memulai transaksi sensitif, seperti melakukan pembayaran, perangkat yang didukung dan menjalankan Android 9 (level API 28) atau yang lebih tinggi memungkinkan Anda menggunakan Konfirmasi Dilindungi oleh Android. Saat menggunakan alur kerja ini, aplikasi Anda akan menampilkan prompt kepada pengguna untuk meminta mereka menyetujui pernyataan singkat yang menegaskan kembali niat mereka untuk menyelesaikan transaksi sensitif.

Jika pengguna menyetujui pernyataan tersebut, aplikasi Anda dapat menggunakan kunci dari Android Keystore untuk menandatangani pesan yang ditampilkan dalam dialog. Tanda tangan tersebut menunjukkan, dengan keyakinan sangat tinggi, bahwa pengguna telah melihat pernyataan tersebut dan telah menyetujuinya.

Perhatian: Konfirmasi Dilindungi oleh Android tidak menyediakan saluran informasi yang aman bagi pengguna. Aplikasi Anda tidak dapat mengasumsikan adanya jaminan kerahasiaan selain yang ditawarkan platform Android. Secara khusus, jangan gunakan alur kerja ini untuk menampilkan informasi sensitif yang biasanya tidak akan Anda tampilkan di perangkat pengguna.

Setelah pengguna mengonfirmasi pesan, integritas pesan akan terjamin, tetapi aplikasi Anda tetap harus menggunakan enkripsi data dalam pengiriman untuk melindungi kerahasiaan pesan yang ditandatangani.

Untuk memberikan dukungan konfirmasi pengguna dengan kepastian tinggi di aplikasi Anda, selesaikan langkah-langkah berikut:

  1. Buat kunci penandatanganan asimetris menggunakan class KeyGenParameterSpec.Builder. Saat membuat kunci, teruskan true ke setUserConfirmationRequired(). Selain itu, panggil setAttestationChallenge() dengan meneruskan nilai tantangan yang sesuai dan disediakan oleh pihak tepercaya.

  2. Daftarkan kunci yang baru dibuat dan sertifikat pengesahan kunci Anda dengan pihak tepercaya yang sesuai.

  3. Kirim detail transaksi ke server Anda dan minta server tersebut membuat serta menampilkan objek besar biner (BLOB) dari data tambahan. Data tambahan mungkin termasuk data yang akan dikonfirmasi atau petunjuk penguraian, seperti lokalitas string prompt.

    Untuk implementasi yang lebih aman, BLOB harus berisi nonce kriptografis untuk perlindungan terhadap serangan replay dan untuk menghilangkan kerancuan transaksi.

  4. Siapkan objek ConfirmationCallback yang memberi tahu aplikasi Anda saat pengguna telah menyetujui prompt yang ditampilkan pada dialog konfirmasi:

    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.
      }
    }

    Jika pengguna menyetujui dialog tersebut, callback onConfirmed() akan dipanggil. BLOB dataThatWasConfirmed adalah struktur data CBOR yang berisi, di antara detail lainnya, teks prompt yang dilihat pengguna serta data tambahan yang Anda teruskan ke builder ConfirmationPrompt. Gunakan kunci yang dibuat sebelumnya untuk menandatangani BLOB dataThatWasConfirmed, lalu teruskan BLOB ini, bersama dengan detail tanda tangan dan transaksi, kembali ke pihak tepercaya.

    Untuk sepenuhnya menggunakan jaminan keamanan yang ditawarkan Konfirmasi Dilindungi oleh Android, pihak tepercaya harus melakukan langkah-langkah berikut setelah menerima pesan yang ditandatangani:

    1. Periksa tanda tangan pada pesan serta rantai sertifikat pengesahan dari kunci penandatanganan.
    2. Periksa apakah sertifikat pengesahan menetapkan flag TRUSTED_CONFIRMATION_REQUIRED, yang menunjukkan bahwa kunci penandatanganan memerlukan konfirmasi pengguna tepercaya. Jika kunci penandatanganan adalah kunci RSA, periksa apakah kunci tersebut tidak memiliki properti PURPOSE_ENCRYPT atau PURPOSE_DECRYPT.
    3. Periksa extraData untuk memastikan bahwa pesan konfirmasi ini milik permintaan baru dan belum diproses. Langkah ini melindungi terhadap serangan replay.
    4. Uraikan promptText untuk mendapatkan informasi tentang tindakan atau permintaan yang dikonfirmasi. Ingatlah bahwa promptText adalah satu-satunya bagian dari pesan yang benar-benar dikonfirmasikan oleh pengguna. Pihak tepercaya tidak boleh berasumsi bahwa data yang harus dikonfirmasi disertakan dalam extraData sesuai dengan promptText.
  5. Tambahkan logika serupa dengan yang ditampilkan dalam cuplikan kode berikut untuk menampilkan dialog itu sendiri:

    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);

Referensi lainnya

Untuk mengetahui informasi selengkapnya tentang Konfirmasi Dilindungi oleh Android, lihat referensi berikut.

Blog