Tìm hiểu trạng thái bảo mật của thiết bị

Ứng dụng của bạn chỉ an toàn khi hệ điều hành cơ bản của ứng dụng an toàn. Để giảm thiểu rủi ro, ứng dụng của bạn nên kiểm soát các hoạt động nhạy cảm về bảo mật bằng cách đánh giá trạng thái bảo mật của thiết bị theo thời gian thực, xác định xem thiết bị (đặc biệt là các thành phần hệ thống cốt lõi) đã được cập nhật đầy đủ và được bảo vệ khỏi các lỗ hổng bảo mật được công bố trong Bản tin bảo mật Android hay chưa. Thông tin về trạng thái bảo mật của thiết bị giúp bạn thiết lập các biện pháp bảo vệ trước khi ứng dụng thực hiện các thao tác có độ rủi ro cao.

AndroidX Security State là một thư viện Jetpack cung cấp quyền truy cập hợp nhất vào trạng thái bảo mật của một thiết bị chạy Android. Dịch vụ này kết hợp các API AOSP và nguồn cấp dữ liệu công khai về lỗ hổng bảo mật của Android để cung cấp trạng thái bảo mật toàn diện, chính xác và có thể hành động cho thiết bị, chứ không chỉ là cấp bản vá bảo mật (SPL).

Tổng quan về kiến trúc

Sơ đồ sau đây minh hoạ cách thư viện Trạng thái bảo mật AndroidX hợp nhất các thuộc tính nền tảng trên thiết bị, nhà cung cấp dịch vụ cập nhật giao tiếp giữa các quy trình (IPC) và nguồn cấp dữ liệu công khai về lỗ hổng bảo mật thành một tập hợp API duy nhất, gắn kết.

Thư viện Trạng thái bảo mật AndroidX hợp nhất các thuộc tính nền tảng trên thiết bị, nhà cung cấp thông tin cập nhật IPC và nguồn cấp dữ liệu công khai về lỗ hổng bảo mật thành một bộ API hợp nhất

Trạng thái và thành phần của bản vá bảo mật

Ưu điểm chính của việc sử dụng thư viện Security State là khả năng cung cấp Cấp bản vá bảo mật (SPL) ở cấp thành phần chi tiết. Trong những năm qua, Android đã giới thiệu thêm nhiều mô-đun cho các bản cập nhật hệ thống Google Play (Project Mainline). Các mô-đun này được cập nhật bằng Google Play độc lập với các bản cập nhật hệ thống qua mạng (OTA) tiêu chuẩn, cung cấp các bản sửa lỗi bảo mật quan trọng theo một nhịp độ khác.

Tương tự, mặc dù cấp bản vá bảo mật thường yêu cầu phiên bản Hình ảnh chung của nhân (GKI) tối thiểu bắt buộc, nhưng các bản cập nhật nhân thực sự có thể đi trước lịch trình hệ thống. Những bản sửa lỗi dành riêng cho nhân này có thể không được chuỗi SPL chính của hệ thống ghi lại đầy đủ.

Để cải thiện tính minh bạch, thư viện trạng thái bảo mật cung cấp một cấp bản vá hiệu quả cho cả 3 thành phần riêng lẻ:

  • Hệ thống (COMPONENT_SYSTEM): Thể hiện trạng thái bảo mật của hệ thống và hệ điều hành tiêu chuẩn, được lấy từ trường cấp bản vá bảo mật tiêu chuẩn.
  • Các mô-đun chính của hệ thống (COMPONENT_SYSTEM_MODULES): Biểu thị trạng thái bảo mật của các thành phần hệ thống mô-đun (bản cập nhật hệ thống Google Play), được lấy từ các phiên bản phát hành mô-đun cụ thể.
  • Kernel (COMPONENT_KERNEL): Biểu thị trạng thái bảo mật của kernel thiết bị, bắt nguồn trực tiếp từ chuỗi phiên bản Kernel.

Tuỳ thuộc vào thành phần, thư viện này cung cấp tối đa 3 phương diện thông tin về cấp bản vá:

  • SPL thiết bị (DSPL): Cấp bản vá hiện tại của từng thành phần đang chạy trên thiết bị, được truy vấn đồng bộ mà không cần yêu cầu mạng. Ngày trong lịch của báo cáo Hệ thống và Mainline (DateBasedSecurityPatchLevel), trong khi Kernel báo cáo phiên bản phát hành (VersionedSecurityPatchLevel, ví dụ: 5.15.148).
  • SPL đã xuất bản (PSPL): Đường cơ sở được công bố chính thức trong Bản tin về bảo mật Android và báo cáo cơ sở dữ liệu Các lỗ hổng bảo mật nguồn mở (OSV). Ứng dụng của bạn có thể đánh giá mức độ tuân thủ bằng cách so sánh ngày hoặc chuỗi phiên bản do SPL của thiết bị cung cấp.
  • SPL hiện có (ASPL): Cho biết liệu thiết bị có bản cập nhật đang chờ xử lý do nhà cung cấp dịch vụ cập nhật cung cấp hay không, được truy vấn không đồng bộ bằng IPC. Tính năng cập nhật hệ thống Google Play trên Android cung cấp các mô-đun Mainline và các ứng dụng OTA của OEM cung cấp các bản cập nhật hệ thống. Vì các bản cập nhật nhân hệ điều hành được gói vào hình ảnh hệ thống, nên khả năng cung cấp bản cập nhật nhân hệ điều hành được đánh giá bằng COMPONENT_SYSTEM.

Các tính năng bảo mật cổng

Bạn có thể kết hợp thông tin từ SPL thiết bị (DSPL), SPL có sẵn (ASPL) và SPL đã xuất bản (PSPL) để đưa ra quyết định theo bối cảnh cho các tính năng bảo mật nhạy cảm. Ví dụ: bạn có thể so sánh DSPL cùng với ASPL để xác định xem có bản vá bảo mật mới hơn mà người dùng chưa cài đặt hay không, nhắc họ cập nhật trước khi bắt đầu các thao tác nhạy cảm như thanh toán hoặc đăng ký thông tin đăng nhập. Bạn cũng có thể dùng areCvesPatched() để xác minh xem các lỗ hổng cụ thể, có mức độ rủi ro cao đã được khắc phục trên thiết bị hay chưa trước khi gọi các hệ thống con dễ bị tấn công, chẳng hạn như kiểm tra các lỗ hổng nghiêm trọng về NFC hoặc Bluetooth trước khi cho phép thanh toán dựa trên khoảng cách hoặc chia sẻ dữ liệu.

Những điều cần cân nhắc về phiên bản nền tảng

Một số chức năng trạng thái bảo mật phụ thuộc vào cấu trúc nền tảng cơ bản và không có trên các phiên bản Android thấp hơn:

  • Android 11 (cấp độ API 30) trở lên: Hỗ trợ đầy đủ cho tất cả các thành phần, bao gồm cả các phiên bản LTS (hỗ trợ dài hạn) của nhân hệ điều hành được phát hành trong bản tin và các truy vấn về khả năng cập nhật (ASPL).
  • Android 10 (API cấp 29): Hỗ trợ các cấp bản vá của hệ thống và mô-đun hệ thống; tuy nhiên, các phiên bản kernel được công bố trong bản tin không có sẵn vì tính năng theo dõi Hình ảnh kernel chung (GKI) và các mục tiêu LTS của kernel trong Bản tin bảo mật Android bắt đầu từ Android 11 – phiên bản kernel trên thiết bị vẫn có thể được đọc cục bộ.
  • Android 9 (cấp độ API 28) trở xuống: Ngoài các hạn chế của Android 10, các thành phần hệ thống theo mô-đun (Dự án Mainline) không tồn tại trước Android 10. Việc gọi getDeviceSecurityPatchLevel(COMPONENT_SYSTEM_MODULES) sẽ quay về ngày cơ sở của kỷ nguyên Unix (1970-01-01) một cách an toàn khi SPL của mô-đun hệ thống không có sẵn.

Tìm hiểu về phạm vi cung cấp bản cập nhật và SPL có sẵn (ASPL)

Để xác định trạng thái bảo mật của thiết bị, bạn cần biết liệu có bản cập nhật bảo mật đang chờ xử lý cho từng thành phần hay không. Các thiết bị Android nhận được bản cập nhật bảo mật thông qua nhiều cơ chế phân phối riêng biệt, chẳng hạn như bản cập nhật hệ thống không dây (OTA)bản cập nhật hệ thống Google Play cho các thành phần mô-đun.

Trước khi ứng dụng của bạn có thể truy xuất ASPL cho một thành phần nhất định, nhà cung cấp bản cập nhật tương ứng phải xuất bản thông tin đó. Để phối hợp trên các nguồn cập nhật khác nhau này, các ứng dụng khách sử dụng thư viện Trạng thái bảo mật AndroidX để truy vấn trạng thái bảo mật, trong khi các ứng dụng cập nhật trên thiết bị sử dụng thư viện Trình cung cấp trạng thái bảo mật AndroidX đi kèm để xuất bản Cấp độ bản vá bảo mật hiện có (ASPL).

Google cung cấp thông tin cập nhật cho các mô-đun Mainline cho tất cả thiết bị Android có GMS, cũng như thông tin OTA hệ thống cho các thiết bị sử dụng ứng dụng OTA của Google (GOTA).

Sơ đồ sau đây minh hoạ cách các ứng dụng sử dụng thư viện Trạng thái bảo mật AndroidX để truy vấn trạng thái bảo mật trên cả bản cập nhật hệ thống Google Play và bản cập nhật OTA hệ thống:

Các ứng dụng khách sử dụng thư viện Trạng thái bảo mật AndroidX để truy vấn trạng thái bảo mật trên cả bản cập nhật hệ thống Google Play và bản cập nhật OTA hệ thống

Thêm phần phụ thuộc

Để thêm một phần phụ thuộc trên AndroidX Security State, bạn phải thêm kho lưu trữ Google Maven vào dự án. Thêm phần phụ thuộc vào tệp build.gradle.kts hoặc build.gradle của ứng dụng:

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

Ma trận quyền đã khai báo

API mục tiêu Các quyền bắt buộc trong AndroidManifest.xml Ghi chú về hoạt động
getDeviceSecurityPatchLevel() Không có Đọc các thuộc tính hệ thống gốc cục bộ và siêu dữ liệu gói một cách đồng bộ.
fetchAvailableSecurityPatchLevel()
queryAllAvailableUpdates()
Không có Giao tiếp bằng IPC trên thiết bị. Thư viện này chỉ truy vấn các thành phần đáng tin cậy trên thiết bị (yêu cầu nhà cung cấp dịch vụ cập nhật phải có quyền đặc quyền READ_PRIVILEGED_PHONE_STATE), vì vậy, ứng dụng của bạn có thể tin tưởng vào tính xác thực của thông tin mà ứng dụng nhận được.
createVulnerabilityReportUrl()
loadVulnerabilityReport()
getPublishedSecurityPatchLevel()
areCvesPatched()
isDeviceFullyUpdated()
android.permission.INTERNET Bắt buộc để tìm nạp báo cáo OSV công khai. Sau khi được tải vào bộ nhớ bằng loadVulnerabilityReport(), các phương thức truy vấn sẽ thực thi cục bộ mà không cần quyền truy cập mạng.

Khởi chạy thư viện

Khởi chạy SecurityPatchState bằng Context Android:

Kotlin

import androidx.security.state.SecurityPatchState

val securityPatchState = SecurityPatchState(context)

Java

import androidx.security.state.SecurityPatchState;

SecurityPatchState securityPatchState = new SecurityPatchState(context);

Việc khởi động bằng context sẽ cung cấp quyền truy cập ngay lập tức vào các cấp bản vá của thiết bị khi không có mạng mà không cần các phần phụ thuộc mạng. (Cập nhật các truy vấn về tình trạng còn hàng, giao tiếp không đồng bộ với các nhà cung cấp trên thiết bị).

Nếu ứng dụng của bạn đánh giá việc tuân thủ CVE và đã tải báo cáo lỗ hổng bảo mật OSV vào bộ nhớ, thì các phương thức gọi Kotlin có thể truyền trực tiếp chuỗi JSON đến hàm khởi tạo trong Kotlin:

val securityPatchState = SecurityPatchState(context, vulnerabilityReportJsonString = jsonString)

Trong Java hoặc khi tải báo cáo không đồng bộ sau khi khởi động, hãy khởi chạy bằng ngữ cảnh và gọi securityPatchState.loadVulnerabilityReport(jsonString).

Kiểm tra cấp độ bản vá của thiết bị

Truy vấn đồng bộ các cấp độ vá trên thiết bị:

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
}

Kiểm tra xem có bản cập nhật hệ thống nào đang chờ xử lý không

Các ứng dụng có thể đánh giá khả năng cung cấp bản cập nhật đang chờ xử lý bằng cách giao tiếp không đồng bộ với các nhà cung cấp bản cập nhật đáng tin cậy trên thiết bị, thường là các bản cập nhật hệ thống Google Play và ứng dụng OTA của OEM:

  • fetchAvailableSecurityPatchLevel(): Trả về SPL (Bản vá bảo mật) có hiệu lực hiện có cho một thành phần cụ thể (quay lại SPL của Thiết bị hiện tại nếu không có bản cập nhật mới hơn) có thể dùng để so sánh với SPL của Thiết bị và SPL đã xuất bản.
  • queryAllAvailableUpdates(): Khám phá tất cả nhà cung cấp bản cập nhật đáng tin cậy trên thiết bị và trả về UpdateCheckResult chi tiết cùng với siêu dữ liệu về nguồn và độ mới của dữ liệu.

Ví dụ 1: Nhắc người dùng về các bản cập nhật đang chờ xử lý

Sử dụng fetchAvailableSecurityPatchLevel() để nhắc người dùng khi có bản cập nhật bảo mật (ví dụ: bằng cách chạy 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

Trong Java, các phương thức không đồng bộ sẽ trả về ListenableFuture và định tuyến các lệnh gọi lại bằng 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));

Ví dụ 2: Kiểm tra trạng thái chi tiết của nhà cung cấp

Sử dụng queryAllAvailableUpdates() để kiểm tra từng nhà cung cấp, dấu thời gian và bản ghi 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));

Xác minh giải pháp cho lỗ hổng bảo mật và kiểm tra CVE

Để đánh giá các biện pháp giảm thiểu CVE, hãy kiểm tra mức độ tuân thủ bản cập nhật tổng thể hoặc kiểm tra Cấp bản vá bảo mật đã phát hành (PSPL), trước tiên, ứng dụng của bạn phải lấy và tải báo cáo lỗ hổng bảo mật OSV, như được trình bày chi tiết trong tài liệu tham khảo API cho 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);

Tải báo cáo lỗ hổng bảo mật

  1. Làm mới WorkManager và bộ nhớ đệm cục bộ: Vì Bản tin bảo mật Android được xuất bản hằng tháng, hãy lưu JSON đã tải xuống vào bộ nhớ trong (context.filesDir) và lên lịch một tác vụ định kỳ trong nền bằng WorkManager (tốt nhất là sau mỗi 24 – 48 giờ) để làm mới báo cáo, đọc từ bộ nhớ đệm cục bộ một cách đồng bộ khi khởi chạy ứng dụng.
  2. Luồng trên nền: Gọi loadVulnerabilityReport() trên một luồng nền (Dispatchers.IO trong Kotlin hoặc Executor trong Java) để tránh chặn luồng giao diện người dùng chính trong khi phân tích cú pháp các bản ghi CVE.
  3. Đánh giá LTS của nhân: Việc gọi getPatchedCves(COMPONENT_KERNEL, ...) sẽ tạo ra một IllegalArgumentExceptionareCvesPatched() không đánh giá các CVE của nhân. Thay vào đó, hãy đánh giá tính bảo mật của nhân bằng cách so sánh phiên bản nhân của thiết bị với các mục tiêu LTS của Nhân chung Android do getPublishedSecurityPatchLevel(COMPONENT_KERNEL) trả về, khớp với nhánh chính và nhánh phụ của nhân đó (ví dụ: so sánh nhân 5.15.140 với mục tiêu 5.15.159).

Tài nguyên khác

Để biết thêm thông tin về trạng thái bảo mật của thiết bị, hãy xem các tài nguyên sau:

Tài liệu

Tài liệu tham khảo API