Memahami status keamanan perangkat

Keamanan aplikasi Anda hanya seaman OS yang mendasarinya. Untuk mengurangi risiko, aplikasi Anda harus membatasi operasi yang sensitif terhadap keamanan dengan penilaian real-time terhadap postur keamanan perangkat, yang menentukan apakah perangkat, terutama komponen sistem intinya, telah diupdate sepenuhnya dan dilindungi dari kerentanan yang dipublikasikan dalam Buletin Keamanan Android. Visibilitas ke status keamanan perangkat membantu Anda membuat pengamanan sebelum aplikasi Anda menjalankan operasi berisiko tinggi.

Status Keamanan AndroidX adalah library Jetpack yang menyediakan akses terpadu ke status keamanan perangkat berteknologi Android. Fitur ini menggabungkan API AOSP dan feed kerentanan publik Android untuk memberikan status keamanan perangkat yang komprehensif, presisi, dan dapat ditindaklanjuti, tidak hanya Tingkat Patch Keamanan (SPL).

Ringkasan arsitektur

Diagram berikut mengilustrasikan cara library Status Keamanan AndroidX menyatukan properti platform di perangkat, penyedia update komunikasi antar-proses (IPC), dan feed kerentanan publik ke dalam satu set API yang kohesif.

Library Status Keamanan AndroidX menyatukan properti platform di perangkat, penyedia update IPC, dan feed kerentanan publik ke dalam serangkaian API terpadu

Status dan komponen patch keamanan

Keuntungan utama menggunakan library Status Keamanan adalah kemampuannya untuk memberikan Tingkat Patch Keamanan (SPL) pada tingkat komponen yang terperinci. Selama bertahun-tahun, Android telah memperkenalkan lebih banyak modul ke update sistem Google Play (Project Mainline) yang diupdate menggunakan Google Play secara terpisah dari update sistem melalui jaringan (OTA) standar, sehingga memberikan perbaikan keamanan penting dengan irama yang berbeda.

Demikian pula, meskipun tingkat patch keamanan biasanya mewajibkan versi Generic Kernel Image (GKI) minimum yang diperlukan, update kernel sebenarnya dapat mendahului jadwal sistem. Perbaikan khusus kernel ini mungkin tidak sepenuhnya tercakup oleh string SPL utama sistem.

Untuk meningkatkan transparansi, library status keamanan menyediakan tingkat patch yang efektif untuk ketiga komponen secara terpisah:

  • Sistem (COMPONENT_SYSTEM): Merepresentasikan OS standar dan status keamanan sistem yang berasal dari kolom tingkat patch keamanan standar.
  • Modul Utama Sistem (COMPONENT_SYSTEM_MODULES): Mewakili status keamanan komponen sistem modular (update sistem Google Play), yang berasal dari versi rilis modul tertentu.
  • Kernel (COMPONENT_KERNEL): Menampilkan status keamanan kernel perangkat, yang diperoleh langsung dari string versi Kernel.

Bergantung pada komponennya, library menyediakan hingga 3 dimensi informasi tingkat patch:

  • SPL Perangkat (DSPL): Tingkat patch saat ini dari setiap komponen yang berjalan di perangkat, dikueri secara serentak tanpa permintaan jaringan. Tanggal kalender laporan Sistem dan Mainline (DateBasedSecurityPatchLevel), sementara Kernel melaporkan versi rilisnya (VersionedSecurityPatchLevel, misalnya, 5.15.148).
  • SPL yang Dipublikasikan (PSPL): Dasar yang dipublikasikan secara resmi dalam laporan database Kerentanan Open Source (OSV) dan Buletin Keamanan Android. Aplikasi Anda dapat mengevaluasi kepatuhan dengan membandingkan tanggal atau string versi yang diberikan oleh SPL Perangkat.
  • SPL yang Tersedia (ASPL): Menunjukkan apakah perangkat memiliki update tertunda yang tersedia dari penyedia update, yang dikueri secara asinkron menggunakan IPC. Fitur update sistem Google Play Android menyediakan ketersediaan untuk modul Mainline, dan klien OTA OEM menyediakan ketersediaan untuk Update sistem. Karena update kernel disertakan dalam image sistem operasi, ketersediaan update kernel dievaluasi menggunakan COMPONENT_SYSTEM.

Membatasi akses ke fitur yang sensitif terhadap keamanan

Anda dapat menggabungkan informasi dari SPL Perangkat (DSPL), SPL yang Tersedia (ASPL), dan SPL yang Dipublikasikan (PSPL) untuk membuat penentuan kontekstual untuk membatasi fitur yang sensitif terhadap keamanan. Misalnya, Anda dapat membandingkan DSPL bersama ASPL untuk menentukan apakah patch keamanan yang lebih baru tersedia dan belum diinstal oleh pengguna, sehingga meminta mereka untuk mengupdate sebelum memulai operasi sensitif seperti pembayaran atau pendaftaran kredensial. Anda juga dapat menggunakan areCvesPatched() untuk memverifikasi apakah kerentanan spesifik dan berisiko tinggi telah diperbaiki di perangkat sebelum memanggil subsistem yang rentan, seperti memeriksa kerentanan NFC atau Bluetooth yang kritis sebelum mengizinkan pembayaran atau berbagi data berbasis kedekatan.

Pertimbangan versi platform

Kemampuan status keamanan tertentu bergantung pada arsitektur platform yang mendasarinya dan tidak tersedia di versi Android yang lebih rendah:

  • Android 11 (level API 30) dan yang lebih tinggi: Dukungan penuh untuk semua komponen, termasuk versi LTS kernel yang dipublikasikan dalam buletin dan kueri ketersediaan update (ASPL).
  • Android 10 (level API 29): Mendukung level patch sistem dan modul sistem; namun, versi kernel yang dipublikasikan dalam buletin tidak tersedia karena pelacakan Generic Kernel Image (GKI) dan target LTS kernel dalam Buletin Keamanan Android dimulai di Android 11—versi kernel di perangkat masih dapat dibaca secara lokal.
  • Android 9 (level API 28) dan yang lebih lama: Selain batasan Android 10, komponen sistem modular (Project Mainline) tidak ada sebelum Android 10. Panggilan getDeviceSecurityPatchLevel(COMPONENT_SYSTEM_MODULES) akan kembali ke tanggal epoch Unix dasar (1970-01-01) dengan aman jika SPL modul sistem tidak tersedia.

Memahami ketersediaan update dan SPL yang Tersedia (ASPL)

Menentukan postur keamanan perangkat memerlukan pengetahuan tentang apakah update keamanan yang tertunda tersedia untuk setiap komponen. Perangkat Android menerima update keamanan melalui beberapa mekanisme pengiriman yang berbeda seperti update sistem melalui udara (OTA) dan update sistem Google Play untuk komponen modular.

Sebelum aplikasi Anda dapat mengambil ASPL untuk komponen tertentu, penyedia update yang sesuai harus memublikasikan informasi tersebut. Untuk berkoordinasi di berbagai sumber update ini, aplikasi klien menggunakan library Status Keamanan AndroidX untuk membuat kueri status keamanan, sementara klien update di perangkat menggunakan library Penyedia Status Keamanan AndroidX pendamping untuk memublikasikan Tingkat Patch Keamanan yang Tersedia (ASPL).

Google memberikan informasi update untuk modul Mainline ke semua perangkat Android GMS, serta informasi OTA sistem untuk perangkat yang menggunakan klien OTA Google (GOTA).

Diagram berikut menggambarkan cara aplikasi klien menggunakan library Status Keamanan AndroidX untuk mengkueri postur keamanan di seluruh update sistem Google Play dan update OTA sistem:

Aplikasi klien menggunakan library Status Keamanan AndroidX untuk mengkueri postur keamanan di seluruh update sistem Google Play dan update OTA sistem

Menambahkan dependensi

Untuk menambahkan dependensi pada Status Keamanan AndroidX, Anda harus menyertakan repositori Maven Google dalam project Anda. Tambahkan dependensi ke file build.gradle.kts atau build.gradle aplikasi Anda:

Kotlin

// Kotlin DSL (build.gradle.kts)
dependencies {
    implementation("androidx.security:security-state:1.1.0")
}

Groovy

// Groovy DSL (build.gradle)
dependencies {
    implementation "androidx.security:security-state:1.1.0"
}

Matriks izin yang dideklarasikan

API Target Izin yang Diperlukan di AndroidManifest.xml Catatan Operasional
getDeviceSecurityPatchLevel() Tidak ada Membaca properti sistem native dan metadata paket lokal secara sinkron.
fetchAvailableSecurityPatchLevel()
queryAllAvailableUpdates()
Tidak ada Berkomunikasi menggunakan IPC di perangkat. Library hanya mengkueri komponen tepercaya di perangkat (yang mengharuskan penyedia update memegang izin READ_PRIVILEGED_PHONE_STATE yang memiliki hak istimewa), sehingga aplikasi Anda dapat yakin dengan keaslian informasi yang diterimanya.
createVulnerabilityReportUrl()
loadVulnerabilityReport()
getPublishedSecurityPatchLevel()
areCvesPatched()
isDeviceFullyUpdated()
android.permission.INTERNET Diperlukan untuk mengambil laporan OSV publik. Setelah dimuat ke dalam memori menggunakan loadVulnerabilityReport(), metode kueri dijalankan secara lokal tanpa akses jaringan.

Melakukan inisialisasi library

Lakukan inisialisasi SecurityPatchState dengan Context Android:

Kotlin

import androidx.security.state.SecurityPatchState

val securityPatchState = SecurityPatchState(context)

Java

import androidx.security.state.SecurityPatchState;

SecurityPatchState securityPatchState = new SecurityPatchState(context);

Melakukan inisialisasi dengan context saja memberikan akses langsung ke tingkat patch perangkat offline tanpa dependensi jaringan. (Perbarui kueri ketersediaan berkomunikasi secara asinkron dengan penyedia di perangkat).

Jika aplikasi Anda mengevaluasi kepatuhan CVE dan telah memuat laporan kerentanan OSV ke dalam memori, pemanggil Kotlin dapat meneruskan string JSON langsung ke konstruktor di Kotlin:

val securityPatchState = SecurityPatchState(context, vulnerabilityReportJsonString = jsonString)

Di Java, atau saat memuat laporan secara asinkron setelah startup, lakukan inisialisasi dengan konteks dan panggil securityPatchState.loadVulnerabilityReport(jsonString).

Memeriksa tingkat patch perangkat

Membuat kueri tingkat patch di perangkat secara sinkron:

Kotlin

val deviceSpl = securityPatchState.getDeviceSecurityPatchLevel(SecurityPatchState.COMPONENT_SYSTEM)
val mainlineSpl = securityPatchState.getDeviceSecurityPatchLevel(SecurityPatchState.COMPONENT_SYSTEM_MODULES)
val kernelVersion = securityPatchState.getDeviceSecurityPatchLevel(SecurityPatchState.COMPONENT_KERNEL)

// Gatekeeping check: compare against a required baseline patch date
val requiredSpl = SecurityPatchState.DateBasedSecurityPatchLevel.fromString("2026-01-01")
if (deviceSpl < requiredSpl) {
    // Restrict access to sensitive features or guide user to update
}

Java

SecurityPatchState.SecurityPatchLevel deviceSpl = securityPatchState.getDeviceSecurityPatchLevel(SecurityPatchState.COMPONENT_SYSTEM);
SecurityPatchState.SecurityPatchLevel mainlineSpl = securityPatchState.getDeviceSecurityPatchLevel(SecurityPatchState.COMPONENT_SYSTEM_MODULES);
SecurityPatchState.SecurityPatchLevel kernelVersion = securityPatchState.getDeviceSecurityPatchLevel(SecurityPatchState.COMPONENT_KERNEL);

// Gatekeeping check: compare against a required baseline patch date
SecurityPatchState.SecurityPatchLevel requiredSpl = SecurityPatchState.DateBasedSecurityPatchLevel.fromString("2026-01-01");
if (deviceSpl.compareTo(requiredSpl) < 0) {
    // Restrict access to sensitive features or guide user to update
}

Memeriksa update sistem yang tertunda

Aplikasi dapat mengevaluasi ketersediaan update yang tertunda dengan berkomunikasi secara asinkron dengan penyedia update tepercaya di perangkat, yang paling umum adalah update sistem Google Play dan klien OTA OEM:

  • fetchAvailableSecurityPatchLevel(): Menampilkan SPL Tersedia yang efektif untuk komponen tertentu (melakukan penggantian ke SPL Perangkat saat ini jika tidak ada update yang lebih baru) yang dapat digunakan untuk membandingkan dengan SPL Perangkat dan SPL yang Dipublikasikan.
  • queryAllAvailableUpdates(): Menemukan semua penyedia update tepercaya di perangkat dan menampilkan UpdateCheckResult terperinci beserta metadata tentang sumber dan keaktualan data.

Contoh 1: Meminta pengguna melakukan update yang tertunda

Gunakan fetchAvailableSecurityPatchLevel() untuk meminta pengguna melakukan update keamanan jika tersedia (misalnya, dengan meluncurkan Settings.ACTION_SYSTEM_UPDATE_SETTINGS):

Kotlin

import androidx.lifecycle.lifecycleScope
import androidx.security.state.SecurityPatchState
import kotlinx.coroutines.launch

// Pattern A: Prompt users for pending updates (with automatic offline fallback)
lifecycleScope.launch {
    val currentSpl = securityPatchState.getDeviceSecurityPatchLevel(SecurityPatchState.COMPONENT_SYSTEM)
    val availableSpl = securityPatchState.fetchAvailableSecurityPatchLevel(SecurityPatchState.COMPONENT_SYSTEM)
    if (availableSpl > currentSpl) {
        // Prompt the user to install pending updates in system settings
    }
}

Java

Di Java, metode asinkron menampilkan ListenableFuture dan merutekan callback menggunakan ContextCompat.getMainExecutor():

import androidx.core.content.ContextCompat;
import androidx.security.state.SecurityPatchState;
import androidx.security.state.SecurityPatchState.SecurityPatchLevel;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;

// Pattern A: Prompt users for pending updates (with automatic offline fallback)
SecurityPatchLevel currentSpl = securityPatchState.getDeviceSecurityPatchLevel(SecurityPatchState.COMPONENT_SYSTEM);
ListenableFuture<SecurityPatchLevel> availableSpl = securityPatchState.fetchAvailableSecurityPatchLevelAsync(
    SecurityPatchState.COMPONENT_SYSTEM,
    SecurityPatchState.UPDATE_INFO_SERVICE_BINDING_TIMEOUT_MS
);

Futures.addCallback(availableSpl, new FutureCallback<SecurityPatchLevel>() {
    @Override
    public void onSuccess(SecurityPatchLevel available) {
        if (available.compareTo(currentSpl) > 0) {
            // Prompt the user to install pending updates in system settings
        }
    }

    @Override
    public void onFailure(Throwable t) {
        // Handle timeout or IPC communication error
    }
}, ContextCompat.getMainExecutor(context));

Contoh 2: Memeriksa status penyedia yang mendetail

Gunakan queryAllAvailableUpdates() untuk memeriksa setiap penyedia, stempel waktu, dan UpdateInfo:

Kotlin

import androidx.lifecycle.lifecycleScope
import androidx.security.state.SecurityPatchState
import kotlinx.coroutines.launch

// Pattern B: Inspect detailed provider status
lifecycleScope.launch {
    val updateResults = securityPatchState.queryAllAvailableUpdates()
    for (result in updateResults) {
        val provider = result.providerPackageName
        val lastCheck = result.lastCheckTimeMillis
        val updates = result.updates // List<UpdateInfo>
    }
}

Java

import androidx.core.content.ContextCompat;
import androidx.security.state.SecurityPatchState;
import androidx.security.state.UpdateCheckResult;
import androidx.security.state.UpdateInfo;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import java.util.List;

// Pattern B: Inspect detailed provider status
ListenableFuture<List<UpdateCheckResult>> updateResults = securityPatchState.queryAllAvailableUpdatesAsync(
    SecurityPatchState.UPDATE_INFO_SERVICE_BINDING_TIMEOUT_MS
);

Futures.addCallback(updateResults, new FutureCallback<List<UpdateCheckResult>>() {
    @Override
    public void onSuccess(List<UpdateCheckResult> results) {
        for (UpdateCheckResult result : results) {
            String provider = result.getProviderPackageName();
            long lastCheck = result.getLastCheckTimeMillis();
            List<UpdateInfo> updates = result.getUpdates();
        }
    }

    @Override
    public void onFailure(Throwable t) {
        // Handle error
    }
}, ContextCompat.getMainExecutor(context));

Memverifikasi penyelesaian kerentanan dan memeriksa CVE

Untuk mengevaluasi mitigasi CVE, memeriksa kepatuhan update secara keseluruhan, atau memeriksa Level Patch Keamanan yang Dipublikasikan (PSPL), aplikasi Anda harus terlebih dahulu mendapatkan dan memuat laporan kerentanan OSV, seperti yang dijelaskan dalam referensi API untuk SecurityPatchState.

Kotlin

// Load vulnerability report
val reportUrl = SecurityPatchState.createVulnerabilityReportUrl()
// ... download JSON string from reportUrl ...
securityPatchState.loadVulnerabilityReport(jsonString)

// Check overall update compliance against published bulletin
val isFullyUpdated = securityPatchState.isDeviceFullyUpdated()

val cves = listOf("CVE-2019-9501", "CVE-2020-3699", "CVE-2024-0016")
val isPatched = securityPatchState.areCvesPatched(cves)

// Get a list of all patched CVEs for a specific component and SPL
val deviceSpl = securityPatchState.getDeviceSecurityPatchLevel(SecurityPatchState.COMPONENT_SYSTEM)
val patchedSystemCVEs = securityPatchState.getPatchedCves(SecurityPatchState.COMPONENT_SYSTEM, deviceSpl)

// Inspect published SPL and kernel LTS target versions from the bulletin
val publishedSystemSpl = securityPatchState.getPublishedSecurityPatchLevel(SecurityPatchState.COMPONENT_SYSTEM)
val kernelLtsTargets = securityPatchState.getPublishedSecurityPatchLevel(SecurityPatchState.COMPONENT_KERNEL)

Java

// Load vulnerability report
Uri reportUrl = SecurityPatchState.createVulnerabilityReportUrl();
// ... download JSON string from reportUrl ...
securityPatchState.loadVulnerabilityReport(jsonString);

// Check overall update compliance against published bulletin
boolean isFullyUpdated = securityPatchState.isDeviceFullyUpdated();

List<String> cves = Arrays.asList("CVE-2019-9501", "CVE-2020-3699", "CVE-2024-0016");
boolean isPatched = securityPatchState.areCvesPatched(cves);

// Get a list of all patched CVEs for a specific component and SPL
SecurityPatchState.SecurityPatchLevel deviceSpl = securityPatchState.getDeviceSecurityPatchLevel(SecurityPatchState.COMPONENT_SYSTEM);
Map<SecurityPatchState.Severity, Set<String>> patchedSystemCVEs =
    securityPatchState.getPatchedCves(SecurityPatchState.COMPONENT_SYSTEM, deviceSpl);

// Inspect published SPL and kernel LTS target versions from the bulletin
List<SecurityPatchState.SecurityPatchLevel> publishedSystemSpl =
    securityPatchState.getPublishedSecurityPatchLevel(SecurityPatchState.COMPONENT_SYSTEM);
List<SecurityPatchState.SecurityPatchLevel> kernelLtsTargets =
    securityPatchState.getPublishedSecurityPatchLevel(SecurityPatchState.COMPONENT_KERNEL);

Memuat laporan kerentanan

  1. Penyimpanan Lokal & Pembaruan WorkManager: Karena Buletin Keamanan Android dipublikasikan setiap bulan, simpan JSON yang didownload dalam penyimpanan internal (context.filesDir) dan jadwalkan tugas latar belakang berkala dengan WorkManager (sebaiknya setiap 24–48 jam) untuk memperbarui laporan, yang dibaca dari cache lokal secara serentak saat peluncuran aplikasi.
  2. Threading Latar Belakang: Panggil loadVulnerabilityReport() di thread latar belakang (Dispatchers.IO di Kotlin atau Executor di Java) untuk menghindari pemblokiran UI thread utama saat mengurai data CVE.
  3. Evaluasi LTS Kernel: Memanggil getPatchedCves(COMPONENT_KERNEL, ...) akan memunculkan IllegalArgumentException, dan areCvesPatched() tidak mengevaluasi CVE kernel. Sebagai gantinya, evaluasi keamanan kernel dengan membandingkan versi kernel perangkat dengan target LTS Kernel Umum Android yang ditampilkan oleh getPublishedSecurityPatchLevel(COMPONENT_KERNEL) yang cocok dengan cabang utama dan sekundernya (misalnya, membandingkan kernel 5.15.140 dengan target 5.15.159).

Referensi lainnya

Untuk mengetahui informasi selengkapnya tentang status keamanan perangkat, lihat referensi berikut:

Dokumentasi

Referensi API