Android melindungi pengguna dari aplikasi berbahaya dan memberikan pengalaman UI yang tepercaya. Framework Keamanan Aktivitas mencakup aturan dan batasan platform. Aturan dan batasan ini mencegah gangguan UI yang tidak diinginkan, pembajakan tugas, dan ancaman keamanan lainnya. Ancaman ini terkait dengan kapan dan bagaimana komponen aplikasi muncul di layar. Komponen utama framework ini membatasi aktivitas yang dimulai dari latar belakang.
Batasan peluncuran aktivitas latar belakang
Peluncuran Aktivitas Latar Belakang (BAL) terjadi saat aplikasi yang tidak berada di latar depan, tanpa aktivitas yang terlihat, atau PendingIntent yang diterima dari aplikasi lain mencoba memulai aktivitas baru. Ini adalah Peluncuran Aktivitas Latar Belakang (BAL).
Meskipun ada kasus penggunaan yang sah, seperti saat aplikasi jam alarm dimulai, BAL yang tidak dibatasi akan menyebabkan pengalaman pengguna yang buruk dan membuat kerentanan keamanan.
Mengapa dibatasi?
Sejak Android 10 (level API 29), platform telah memberikan batasan kapan aplikasi dapat memulai aktivitas dari latar belakang. Perlindungan ini membantu mencegah perilaku aplikasi berbahaya dan meningkatkan pengalaman pengguna dengan mengurangi penyalahgunaan umum, termasuk:
- Pembajakan UI &Iklan Pop-up: Aplikasi latar belakang tiba-tiba meluncurkan aktivitas (sering kali iklan) di atas aplikasi yang saat ini digunakan pengguna, sehingga membajak sesi mereka.
- Phishing &Peniruan: Aplikasi latar belakang meluncurkan aktivitas yang meniru aplikasi lain (misalnya, layar login palsu untuk aplikasi yang sah) untuk mencuri kredensial pengguna. Hal ini sering kali dilakukan melalui serangan "Activity Sandwich", saat aktivitas berbahaya disisipkan ke dalam tumpukan tugas aplikasi yang sah.
- Tapjacking: Aplikasi latar belakang menampilkan aktivitas transparan atau tersembunyi di atas aplikasi lain untuk mencegat ketukan pengguna dan menipu mereka agar melakukan tindakan yang tidak diinginkan.
- App Awakening: Komponen latar belakang dari satu aplikasi membangunkan komponen latar depan aplikasi lain untuk meningkatkan metrik pengguna aktif harian secara tidak sah.
Layanan latar depan (untuk tugas yang sedang berlangsung)
Jika aplikasi Anda perlu menjalankan tugas yang berjalan lama di latar belakang yang harus diketahui pengguna, seperti memutar musik atau melacak olahraga, Anda harus menggunakan Layanan Latar Depan. Layanan latar depan harus menampilkan notifikasi persisten yang tidak dapat ditutup oleh pengguna. Notifikasi ini dapat memberikan kontrol interaktif (misalnya, tombol putar/jeda untuk aplikasi musik). Hal ini membuat pengguna tetap mengetahui dan mengontrol, tetapi tidak mengganggu mereka dengan aktivitas layar penuh.
Dengan mengikuti hierarki ini—mulai dari notifikasi standar dan hanya meningkat ke opsi yang lebih mengganggu jika diperlukan, Anda akan menciptakan pengalaman yang lebih baik dan lebih dapat diprediksi bagi pengguna.
Kapan aktivitas latar belakang diizinkan (pengecualian)
Aplikasi dapat memulai aktivitas dari latar belakang jika salah satu kondisi berikut terpenuhi:
- Aplikasi memiliki jendela yang terlihat, seperti aktivitas di latar depan.
- Aplikasi adalah Editor Metode Input (IME) saat ini.
- Aktivitas dimulai dari
PendingIntentyang dikirim oleh sistem (misalnya, dari ketukan notifikasi). - Aplikasi memiliki izin
SYSTEM_ALERT_WINDOWyang diberikan oleh pengguna. - Aplikasi telah diberi izin
START_ACTIVITIES_FROM_BACKGROUND. - Aplikasi terikat oleh layanan yang telah diberi izin untuk memulai aktivitas latar belakang.
- Peluncuran dimulai oleh aplikasi peluncur perangkat, seperti saat pengguna mengetuk ikon aplikasi atau berinteraksi dengan widget.
- Peluncuran berasal dari bagian inti sistem operasi yang harus berjalan setiap saat, seperti layanan Telepon yang memulai layar panggilan masuk.
Penguatan baru dan keikutsertaan yang diperlukan
Untuk lebih meningkatkan keamanan, Android telah memperkenalkan aturan yang lebih ketat yang memerlukan keikutsertaan eksplisit untuk aplikasi yang menggunakan PendingIntent dan IntentSender untuk meluncurkan aktivitas. Peluncuran hanya diizinkan jika aplikasi yang membuat PendingIntent atau aplikasi yang mengirimkannya memilih untuk memberikan hak istimewa peluncuran latar belakangnya.
Dalam sebagian besar kasus, aplikasi yang mengirim PendingIntent harus memilih ikut serta, karena biasanya merupakan aplikasi yang berinteraksi langsung dengan pengguna (misalnya, mengetuk tombol).
Pengirim harus memilih ikut serta untuk PendingIntent
Saat menargetkan Android 14 (level API 34) atau yang lebih tinggi, aplikasi Anda tidak lagi memberikan hak istimewa BAL secara default saat mengirim PendingIntent. Jika Anda tidak
memilih ikut serta secara eksplisit, peluncuran aktivitas mungkin akan diblokir, kecuali jika pembuat
dari PendingIntent telah memberikan hak istimewanya sendiri.
Untuk memastikan peluncuran berhasil, pengirim harus memilih ikut serta untuk memberikan hak istimewanya dengan memanggil ActivityOptions.setPendingIntentBackgroundActivityStartMode() dan mode yang direkomendasikan adalah ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOW_IF_VISIBLE (ditambahkan di SDK 36).
Ini adalah mode yang lebih ketat dan lebih aman. Mode ini memberikan izin hanya jika aplikasi pengirim terlihat di layar saat PendingIntent dikirim. Hal ini lebih memastikan bahwa peluncuran aktivitas adalah hasil langsung dari interaksi pengguna dengan aplikasi Anda.
Gunakan ActivityOptions.setPendingIntentBackgroundActivityStartMode() untuk memberikan hak istimewa.
// Sender Side
ActivityOptions options = ActivityOptions.makeBasic()
.setPendingIntentBackgroundActivityStartMode(
ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOW_IF_VISIBLE);
try {
myPendingIntent.send(options.toBundle());
} catch (PendingIntent.CanceledException e) {
Log.e(TAG, "The PendingIntent was canceled", e);
}
// Sender Side
val options = ActivityOptions.makeBasic().apply {
pendingIntentBackgroundActivityStartMode = ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOW_IF_VISIBLE
}
try {
myPendingIntent.send(options.toBundle())
} catch (e: PendingIntent.CanceledException) {
Log.e(TAG, "The PendingIntent was canceled", e)
}
Kreator harus memilih ikut serta untuk PendingIntent
Saat menargetkan Android 15 (level API 35) atau yang lebih tinggi, aplikasi yang membuat PendingIntent tidak lagi memberikan hak istimewa peluncuran latar belakangnya secara default. Untuk mengizinkan pengirim menggunakan hak istimewa BAL aplikasi Anda, Anda harus memilih ikut serta secara eksplisit.
Gunakan ActivityOptions.setPendingIntentCreatorBackgroundActivityStartMode() untuk memberikan hak istimewa.
// Creator Side
Intent intent = new Intent(context, MyActivity.class);
ActivityOptions options = ActivityOptions.makeBasic().setPendingIntentCreatorBackgroundActivityStartMode(ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED);
PendingIntent pendingIntent = PendingIntent.getActivity(context, REQUEST_CODE, intent, PendingIntent.FLAG_IMMUTABLE, options.toBundle());
// Creator Side
val intent = Intent(context, MyActivity::class.java)
val options = ActivityOptions.makeBasic().apply {
pendingIntentCreatorBackgroundActivityStartMode = ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED
}
val pendingIntent = PendingIntent.getActivity(context, REQUEST_CODE, intent,
PendingIntent.FLAG_IMMUTABLE, options.toBundle())
Meluncurkan dengan IntentSender
Batasan BAL yang sama juga berlaku saat meluncurkan aktivitas menggunakan an
IntentSender. Karena IntentSender diperoleh melalui
PendingIntent.getIntentSender, hal ini tunduk pada persyaratan keikutsertaan
yang serupa.
- Mulai Android 14 (API 34) menggunakan Context.startIntentSender()
memerlukan keikutsertaan sisi pengirim. Anda juga harus menyediakan paket
ActivityOptionsdi sini.
ActivityOptions options = ActivityOptions.makeBasic()
.setPendingIntentBackgroundActivityStartMode(
ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED);
context.startIntentSender(myIntentSender, fillInIntent, flagsMask,
flagsValues, extraFlags, options.toBundle());
val options = ActivityOptions.makeBasic().apply {
pendingIntentBackgroundActivityStartMode = ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED
}
context.startIntentSender(myIntentSender, fillInIntent, flagsMask,
flagsValues, extraFlags, options.toBundle())
- Mulai Android 17 (API 37+) menggunakan IntentSender.sendIntent() memerlukan keikutsertaan sisi pengirim.
ActivityOptions options = ActivityOptions.makeBasic()
.setPendingIntentBackgroundActivityStartMode(
ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED);
myIntentSender.sendIntent(context, code, intent, onFinished, handler,
requiredPermission, options.toBundle());
val options = ActivityOptions.makeBasic().apply {
pendingIntentBackgroundActivityStartMode = ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED
}
myIntentSender.sendIntent(context, code, intent, onFinished, handler,
requiredPermission, options.toBundle())
- Menggunakan ActivityResultLauncher
: AndroidX API ini menggunakan Context.startIntentSender() secara internal dan oleh karena itu terpengaruh oleh batasan BAL.
Diagram Urutan: Batasan BAL
Diagram ini menggambarkan proses peluncuran aktivitas yang aman menggunakan PendingIntent. Peluncuran yang berhasil bergantung pada rantai hak istimewa yang valid, dengan setidaknya satu aplikasi yang berpartisipasi memberikan hak istimewanya dan memiliki kemampuan untuk meluncurkan aktivitas dari latar belakang
- Pembuatan &Delegasi (Aplikasi A - Kreator)
- Aplikasi Kreator membangun
PendingIntent - Jika menargetkan SDK 35+, kreator harus secara eksplisit mendelegasikan hak istimewa BAL nya menggunakan setPendingIntentCreatorBackgroundActivityStartMode() jika ingin hak istimewanya digunakan. Secara default, tidak ada hak istimewa yang didelegasikan.
PendingIntentkemudian dikirimkan ke aplikasi lain (Aplikasi B)
- Aplikasi Kreator membangun
- Peluncuran &Kontribusi (Aplikasi B - Pengirim)
- Di lain waktu, aplikasi Pengirim memulai peluncuran dengan memanggil
PendingIntent.send(). - Jika menargetkan SDK 34+, pengirim harus secara eksplisit memberikan hak istimewanya sendiri menggunakan setPendingIntentBackgroundActivityStartMode() jika ingin hak istimewanya digunakan. Secara default, tidak ada hak istimewa yang didelegasikan.
- Di lain waktu, aplikasi Pengirim memulai peluncuran dengan memanggil
- Validasi Keamanan Sistem Android
- Sistem Android mencegat permintaan peluncuran dan melakukan pemeriksaan keamanan.
- Sistem ini mengevaluasi dua kondisi:
- Apakah Kreator mendelegasikan hak istimewanya, DAN apakah aplikasi Kreator saat ini memenuhi salah satu pengecualian BAL umum?
- Apakah Pengirim memberikan hak istimewanya, DAN apakah aplikasi Pengirim saat ini memenuhi salah satu pengecualian BAL umum?
- Hasil
- DIIZINKAN: Jika setidaknya satu dari dua kondisi di langkah 3 terpenuhi, rantai hak istimewa akan divalidasi. Sistem Android memulai aktivitas target, dan pengirim menerima hasil yang berhasil.
- DIBLOKIR: Jika tidak ada kondisi yang terpenuhi, sistem akan memblokir peluncuran. Aplikasi pengirim tidak menerima nilai atau pengecualian yang ditampilkan secara langsung yang menunjukkan kegagalan. Sebagai gantinya, Sistem Android secara internal mencatat pesan "Background activity launch blocked!" ke Logcat, yang harus diperiksa oleh developer untuk proses debug.
Pencegahan Pembajakan Tugas
Untuk mencegah serangan pembajakan dalam tugas (seperti "Activity Sandwich"), Android 15 memperkenalkan aturan baru untuk aplikasi yang menargetkan level API 37 atau yang lebih tinggi.
- Aturan 1: Dalam satu tugas, aktivitas hanya dapat diluncurkan oleh aktivitas lain yang termasuk dalam aplikasi yang sama (yaitu, memiliki UID yang sama) dengan aktivitas teratas saat ini dalam tugas.
- Aturan 2: Hanya aktivitas dalam tugas latar depan yang cocok dengan UID aktivitas teratas yang diizinkan untuk membuat tugas baru atau menampilkan tugas yang berbeda dan ada ke latar depan.
Keikutsertaan developer untuk perlindungan dalam tugas
Perilaku ini dapat diaktifkan mulai dari SDK target 37, Anda harus memilih ikut serta secara eksplisit untuk mengaktifkannya. Fitur ini dirancang untuk mencegah pembajakan dalam tugas (atau Activity Sandwiching), saat aplikasi berbahaya dapat meluncurkan aktivitas ke dalam tugas aplikasi Anda untuk menirunya dan mencuri data pengguna.
Mengaktifkan perlindungan
Untuk memilih ikut serta dan mengaktifkan ASM untuk aplikasi Anda, tetapkan atribut android:allowCrossUidActivitySwitchFromBelow ke false dalam file AndroidManifest.xml. Ini adalah setelan tingkat aplikasi yang melindungi semua aktivitas di aplikasi Anda secara default.
Membuat pengecualian untuk aktivitas tertentu
Jika Anda telah mengaktifkannya untuk aplikasi, tetapi perlu mengizinkan aktivitas tertentu yang tepercaya diluncurkan oleh aplikasi lain, Anda dapat membuat pengecualian yang ditargetkan. Untuk mengecualikan satu aktivitas dari perlindungan ini, panggil setAllowCrossUidActivitySwitchFromBelow(true) dalam metode onCreate() aktivitas tersebut. Hal ini memungkinkan satu aktivitas tersebut diluncurkan, sementara aktivitas lainnya di aplikasi Anda tetap terlindungi.
Pemecahan masalah
Filter Logcat untuk menemukan pesan yang relevan menggunakan ekspresi reguler. Tag ActivityTaskManager sering digunakan, dan pemfilteran menurut ActivityTaskManager dapat membantu mengisolasi log.
Memahami pesan log utama
Peluncuran Diblokir (Error): Pesan ini menunjukkan bahwa peluncuran aktivitas diblokir.
- Artinya: Peluncuran aktivitas ditolak karena keikutsertaan PendingIntent yang diperlukan tidak ada dari pengirim (menargetkan SDK 34+) atau kreator (menargetkan SDK 35+).
- Tindakan: Anda harus mengupdate kode untuk menyertakan keikutsertaan ActivityOptions yang benar.
Saat menganalisis log, periksa kolom berikut:
- realCallingPackage: Aplikasi yang mengirim PendingIntent. Ini adalah pengirim.
- callingPackage: Aplikasi yang membuat PendingIntent. Ini adalah kreator.
Mode Ketat
Mulai Android 16, developer aplikasi dapat mengaktifkan Mode ketat untuk mendapatkan notifikasi saat peluncuran aktivitas diblokir (atau berisiko diblokir saat SDK target aplikasi ditingkatkan).
Contoh kode untuk mengaktifkan dari awal di metode Application.onCreate() Aplikasi, Aktivitas, atau komponen aplikasi lainnya:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
StrictMode.setVmPolicy(
StrictMode.VmPolicy.Builder()
.detectBlockedBackgroundActivityLaunch()
.penaltyLog()
.build());
)
}