برنامه شما فقط به اندازه سیستم عامل اصلی آن ایمن است. برای کاهش ریسک، برنامه شما باید عملیات حساس به امنیت را با ارزیابی بلادرنگ وضعیت امنیتی دستگاه، بررسی کند و مشخص کند که آیا دستگاه، به ویژه اجزای اصلی سیستم آن، به طور کامل بهروزرسانی شده و در برابر آسیبپذیریهای منتشر شده در بولتن امنیتی اندروید محافظت میشود یا خیر. قابلیت مشاهده وضعیت امنیتی دستگاه به شما کمک میکند تا قبل از اجرای عملیات پرخطر توسط برنامه، اقدامات حفاظتی لازم را انجام دهید.
AndroidX Security State یک کتابخانه Jetpack است که دسترسی یکپارچه به وضعیت امنیتی یک دستگاه مبتنی بر اندروید را فراهم میکند. این کتابخانه APIهای AOSP و فیدهای آسیبپذیری عمومی اندروید را ترکیب میکند تا یک وضعیت امنیتی جامع، دقیق و قابل اجرا برای دستگاه، فراتر از سطح وصله امنیتی (SPL) ارائه دهد.
نمای کلی معماری
نمودار زیر نشان میدهد که چگونه کتابخانه وضعیت امنیتی اندروید ایکس، ویژگیهای پلتفرم روی دستگاه، ارائهدهندگان بهروزرسانی ارتباطات بینپردازشی (IPC) و فیدهای آسیبپذیری عمومی را در یک مجموعه واحد و منسجم از APIها یکپارچه میکند.

وضعیتها و اجزای وصلههای امنیتی
مزیت اصلی استفاده از کتابخانه Security State ، توانایی آن در ارائه سطح وصله امنیتی (SPL) در سطح جزئی و جزئی است. در طول سالها، اندروید ماژولهای بیشتری را به بهروزرسانیهای سیستمی گوگل پلی (Project Mainline) معرفی کرده است که با استفاده از گوگل پلی و مستقل از بهروزرسانیهای استاندارد سیستم از طریق هوا (OTA) بهروزرسانی میشوند و رفع اشکالات امنیتی حیاتی را با ریتم متفاوتی ارائه میدهند.
به طور مشابه، در حالی که سطح وصله امنیتی معمولاً حداقل نسخه مورد نیاز Generic Kernel Image (GKI) را الزامی میکند، بهروزرسانیهای هسته در واقع میتوانند جلوتر از برنامه سیستم انجام شوند. این اصلاحات خاص هسته ممکن است به طور کامل توسط رشته SPL اصلی سیستم ثبت نشوند.
برای بهبود شفافیت، کتابخانه وضعیت امنیتی، سطح وصله (patch) مؤثری را برای هر سه مؤلفه به صورت جداگانه ارائه میدهد:
- سیستم (
COMPONENT_SYSTEM): وضعیت استاندارد سیستم عامل و امنیت سیستم را که از فیلد سطح وصله امنیتی استاندارد مشتق شده است، نشان میدهد. - ماژولهای اصلی سیستم (
COMPONENT_SYSTEM_MODULES): وضعیت امنیتی اجزای سیستم ماژولار (بهروزرسانیهای سیستم Google Play) را که از نسخههای انتشار ماژول خاص گرفته شده است، نشان میدهد. - هسته (
COMPONENT_KERNEL): وضعیت امنیتی هسته دستگاه را نشان میدهد که مستقیماً از رشته نسخه هسته استخراج میشود.
بسته به کامپوننت، این کتابخانه تا ۳ بُعد از اطلاعات سطح پچ را ارائه میدهد:
- SPL دستگاه (DSPL): سطح وصله فعلی اجزای منفرد در حال اجرا روی دستگاه، که به صورت همزمان و بدون درخواست شبکه مورد پرسش قرار میگیرد. سیستم و خط اصلی تاریخهای تقویمی را گزارش میدهند (
DateBasedSecurityPatchLevel)، در حالی که هسته نسخه انتشار خود را گزارش میدهد (VersionedSecurityPatchLevel، به عنوان مثال،5.15.148). - SPL منتشر شده (PSPL): خط پایهای که رسماً در بولتن امنیتی اندروید و گزارشهای پایگاه داده آسیبپذیریهای متنباز (OSV) منتشر شده است. برنامه شما میتواند با مقایسه تاریخها یا رشتههای نسخه ارائه شده توسط Device SPL، انطباق را ارزیابی کند.
- SPL موجود (ASPL): نشان میدهد که آیا یک دستگاه بهروزرسانیهای در انتظار از ارائهدهندگان بهروزرسانی دارد یا خیر، که به صورت ناهمزمان با استفاده از IPC بررسی میشود. ویژگی بهروزرسانی سیستم اندروید در گوگل پلی، در دسترس بودن ماژولهای اصلی را فراهم میکند و کلاینتهای OEM OTA در دسترس بودن بهروزرسانیهای سیستم را فراهم میکنند. از آنجا که بهروزرسانیهای هسته در تصویر سیستم عامل قرار دارند، در دسترس بودن بهروزرسانی هسته با استفاده از
COMPONENT_SYSTEMارزیابی میشود.
ویژگیهای حساس به امنیت دروازه
شما میتوانید اطلاعات Device SPL (DSPL)، Available SPL (ASPL) و Published SPL (PSPL) را با هم ترکیب کنید تا برای گیت کردن ویژگیهای حساس به امنیت، تصمیمات زمینهای بگیرید. به عنوان مثال، میتوانید DSPL را در کنار ASPL مقایسه کنید تا مشخص شود که آیا وصله امنیتی جدیدتری که کاربر هنوز نصب نکرده است، در دسترس است یا خیر، و قبل از شروع عملیات حساس مانند پرداختها یا ثبت نام اعتبارنامه، آنها را وادار به بهروزرسانی کنید. همچنین میتوانید از areCvesPatched() برای تأیید اینکه آیا آسیبپذیریهای خاص و پرخطر روی دستگاه قبل از فراخوانی زیرسیستمهای آسیبپذیر، مانند بررسی آسیبپذیریهای حیاتی NFC یا بلوتوث قبل از تأیید پرداختهای مبتنی بر مجاورت یا اشتراکگذاری دادهها، برطرف شدهاند یا خیر، استفاده کنید.
ملاحظات نسخه پلتفرم
برخی از قابلیتهای وضعیت امنیتی به معماری پلتفرم اصلی بستگی دارند و در نسخههای پایینتر اندروید در دسترس نیستند:
- اندروید ۱۱ (API سطح ۳۰) و بالاتر: پشتیبانی کامل از تمام اجزا، شامل نسخههای LTS کرنل منتشر شده توسط بولتن و کوئریهای مربوط به در دسترس بودن بهروزرسانی (ASPL).
- اندروید ۱۰ (سطح API ۲۹): از سیستم و سطوح وصله ماژول سیستم پشتیبانی میکند؛ با این حال، نسخههای کرنل منتشر شده توسط بولتن در دسترس نیستند زیرا ردیابی تصویر کرنل عمومی (GKI) و اهداف LTS کرنل در بولتن امنیتی اندروید از اندروید ۱۱ آغاز شد - نسخه کرنل روی دستگاه هنوز هم میتواند به صورت محلی خوانده شود.
- اندروید ۹ (سطح API 28) و قدیمیتر: علاوه بر محدودیتهای اندروید ۱۰، اجزای سیستم ماژولار (Project Mainline) قبل از اندروید ۱۰ وجود نداشتند. فراخوانی
getDeviceSecurityPatchLevel(COMPONENT_SYSTEM_MODULES)با خیال راحت به تاریخ پایه یونیکس (1970-01-01) برمیگردد، زمانی که SPLهای ماژول سیستم در دسترس نیستند.
درک در دسترس بودن بهروزرسانیها و SPL موجود (ASPL)
تعیین وضعیت امنیتی یک دستگاه مستلزم دانستن این است که آیا بهروزرسانیهای امنیتی در حال انتظار برای اجزای منفرد در دسترس هستند یا خیر. دستگاههای اندروید بهروزرسانیهای امنیتی را از طریق چندین مکانیسم ارائه متمایز مانند بهروزرسانیهای سیستم از طریق هوا (OTA) و بهروزرسانیهای سیستم Google Play برای اجزای ماژولار دریافت میکنند.
قبل از اینکه برنامه شما بتواند ASPL را برای یک جزء خاص بازیابی کند، ارائه دهنده بهروزرسانی مربوطه باید آن اطلاعات را منتشر کند. برای هماهنگی بین این منابع بهروزرسانی مختلف، برنامههای کلاینت از کتابخانه AndroidX Security State برای پرسوجوی وضعیت امنیتی استفاده میکنند، در حالی که کلاینتهای بهروزرسانی روی دستگاه از کتابخانه همراه AndroidX Security State Provider برای انتشار سطح وصله امنیتی موجود (ASPL) خود استفاده میکنند.
گوگل اطلاعات بهروزرسانی ماژولهای Mainline را برای همه دستگاههای اندروید GMS و همچنین اطلاعات سیستم OTA را برای دستگاههایی که از کلاینت Google OTA (GOTA) استفاده میکنند، ارائه میدهد.
نمودار زیر نشان میدهد که چگونه برنامههای کلاینت از کتابخانهی وضعیت امنیتی اندروید ایکس (AndroidX Security State) برای پرسوجو از وضعیت امنیتی در بهروزرسانیهای سیستم گوگل پلی و بهروزرسانیهای OTA سیستم استفاده میکنند:

وابستگیها را اضافه کنید
برای افزودن یک وابستگی به AndroidX Security State، باید مخزن Google Maven را در پروژه خود وارد کنید. این وابستگی را به فایل build.gradle.kts یا build.gradle برنامه خود اضافه کنید:
کاتلین
// Kotlin DSL (build.gradle.kts)
dependencies {
implementation("androidx.security:security-state:1.1.0")
}
گرووی
// Groovy DSL (build.gradle)
dependencies {
implementation "androidx.security:security-state:1.1.0"
}
ماتریس مجوزهای اعلامشده
| API های هدف | مجوزهای مورد نیاز در AndroidManifest.xml | یادداشتهای عملیاتی |
|---|---|---|
getDeviceSecurityPatchLevel() | هیچکدام | ویژگیهای سیستم محلی و فرادادههای بسته را به صورت همزمان میخواند. |
fetchAvailableSecurityPatchLevel()queryAllAvailableUpdates() | هیچکدام | با استفاده از IPC روی دستگاه ارتباط برقرار میکند. این کتابخانه فقط اجزای قابل اعتماد روی دستگاه را جستجو میکند (و ارائه دهندگان بهروزرسانی را ملزم به داشتن مجوز ممتاز READ_PRIVILEGED_PHONE_STATE میکند)، بنابراین برنامه شما میتواند از صحت اطلاعات دریافتی مطمئن باشد. |
createVulnerabilityReportUrl()loadVulnerabilityReport()getPublishedSecurityPatchLevel()areCvesPatched()isDeviceFullyUpdated() | android.permission.INTERNET | برای دریافت گزارشهای عمومی OSV مورد نیاز است. پس از بارگذاری در حافظه با استفاده از loadVulnerabilityReport() ، متدهای کوئری به صورت محلی و بدون دسترسی به شبکه اجرا میشوند. |
مقداردهی اولیه کتابخانه
مقداردهی اولیه SecurityPatchState با یک Android Context :
کاتلین
import androidx.security.state.SecurityPatchState
val securityPatchState = SecurityPatchState(context)
جاوا
import androidx.security.state.SecurityPatchState;
SecurityPatchState securityPatchState = new SecurityPatchState(context);
مقداردهی اولیه با context به تنهایی، دسترسی فوری به سطوح وصله دستگاه آفلاین را بدون وابستگی به شبکه فراهم میکند. (درخواستهای بهروزرسانی برای دسترسی به صورت غیرهمزمان با ارائهدهندگان روی دستگاه ارتباط برقرار میکنند).
اگر برنامه شما انطباق با CVE را ارزیابی میکند و از قبل گزارش آسیبپذیری OSV را در حافظه بارگذاری کرده است، فراخوانیکنندگان کاتلین میتوانند رشته JSON را مستقیماً به سازنده در کاتلین منتقل کنند:
val securityPatchState = SecurityPatchState(context, vulnerabilityReportJsonString = jsonString)
در جاوا، یا هنگام بارگذاری گزارشها به صورت غیرهمزمان پس از راهاندازی، با context مقداردهی اولیه کنید و securityPatchState.loadVulnerabilityReport(jsonString) را فراخوانی کنید.
بررسی سطح پچ دستگاه
جستجوی همزمان سطوح پچ روی دستگاه:
کاتلین
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
}
جاوا
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
}
بررسی بهروزرسانیهای سیستم در انتظار
برنامهها میتوانند با برقراری ارتباط غیرهمزمان با ارائهدهندگان بهروزرسانی مورد اعتماد روی دستگاه، که معمولاً بهروزرسانیهای سیستمی گوگل پلی و کلاینتهای OEM OTA هستند، در دسترس بودن بهروزرسانیهای در حال انتظار را ارزیابی کنند:
-
fetchAvailableSecurityPatchLevel(): مقدار SPL موجود و مؤثر را برای یک کامپوننت مشخصشده برمیگرداند (در صورت عدم وجود بهروزرسانی جدیدتر، به SPL دستگاه فعلی برمیگردد) که میتواند برای مقایسه با SPL دستگاه و SPL منتشر شده استفاده شود. -
queryAllAvailableUpdates(): تمام ارائهدهندگان بهروزرسانی معتبر روی دستگاه را پیدا میکند وUpdateCheckResultجزئی را به همراه فرادادههایی در مورد منبع و تازگی دادهها برمیگرداند.
مثال ۱: کاربران را برای بهروزرسانیهای در حال انتظار مطلع کنید
از fetchAvailableSecurityPatchLevel() برای اطلاعرسانی به کاربران در مورد بهروزرسانیهای امنیتی استفاده کنید (برای مثال، با اجرای Settings.ACTION_SYSTEM_UPDATE_SETTINGS ):
کاتلین
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
}
}
جاوا
در جاوا، متدهای ناهمزمان یک ListenableFuture برمیگردانند و با استفاده از ContextCompat.getMainExecutor() فراخوانیهای مسیر (route callbacks) را انجام میدهند:
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));
مثال ۲: بررسی وضعیت دقیق ارائهدهنده
از queryAllAvailableUpdates() برای بررسی ارائه دهندگان، مهرهای زمانی و رکوردهای UpdateInfo به صورت جداگانه استفاده کنید:
کاتلین
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>
}
}
جاوا
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));
تأیید رفع آسیبپذیری و بررسی CVEها
برای ارزیابی راهکارهای کاهش آسیبپذیری CVE، بررسی انطباق کلی با بهروزرسانیها یا بررسی سطوح وصلههای امنیتی منتشر شده (PSPL)، برنامه شما ابتدا باید گزارش آسیبپذیری OSV را دریافت و بارگذاری کند، همانطور که در مرجع API برای SecurityPatchState به تفصیل شرح داده شده است.
کاتلین
// 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)
جاوا
// 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);
گزارشهای آسیبپذیری را بارگیری کنید
- ذخیرهسازی محلی و بهروزرسانی WorkManager: از آنجا که بولتنهای امنیتی اندروید ماهانه منتشر میشوند، JSON دانلود شده را در حافظه داخلی (
context.filesDir) ذخیرهسازی کنید و یک وظیفه پسزمینه دورهای را باWorkManager(ترجیحاً هر 24 تا 48 ساعت) برنامهریزی کنید تا گزارش را بهروزرسانی کند و همزمان با اجرای برنامه، از حافظه پنهان محلی بخواند. - نخبندی پسزمینه: تابع
loadVulnerabilityReport()را روی یک نخ پسزمینه (Dispatchers.IOدر کاتلین یا یکExecutorدر جاوا) فراخوانی کنید تا از مسدود شدن نخ رابط کاربری اصلی هنگام تجزیه رکوردهای CVE جلوگیری شود. - ارزیابی Kernel LTS: فراخوانی
getPatchedCves(COMPONENT_KERNEL, ...)خطایIllegalArgumentExceptionرا ایجاد میکند وareCvesPatched()CVEهای هسته را ارزیابی نمیکند. در عوض، امنیت هسته را با مقایسه نسخه هسته دستگاه با اهداف Android Common Kernel LTS که توسطgetPublishedSecurityPatchLevel(COMPONENT_KERNEL)برگردانده میشود و با تطبیق شاخه اصلی و فرعی آن (مثلاً مقایسه یک هسته5.15.140با هدف5.15.159) ارزیابی کنید.
منابع اضافی
برای اطلاعات بیشتر در مورد وضعیت امنیتی دستگاه، به منابع زیر مراجعه کنید:
مستندات
- بولتنهای امنیتی اندروید
- اجزای سیستم مدولار
- تصویر هسته عمومی (GKI)
- وصلههای امنیتی تکمیلی
- API یکپارچگی بازی
- پایگاه داده آسیبپذیریهای متنباز (OSV)
- یادداشتهای انتشار نسخه ۱.۱.۰ وضعیت امنیتی