רמת האבטחה של האפליקציה שלכם שווה לזו של מערכת ההפעלה הבסיסית שלה. כדי לצמצם את הסיכון, האפליקציה צריכה להגביל פעולות שקשורות לאבטחה באמצעות הערכה בזמן אמת של מצב האבטחה של המכשיר. ההערכה הזו קובעת אם המכשיר, ובמיוחד רכיבי הליבה של המערכת, מעודכן באופן מלא ומוגן מפני נקודות חולשה שפורסמו בחדשות האבטחה של Android. היכולת לראות את מצב האבטחה של המכשיר עוזרת לכם להגדיר אמצעי הגנה לפני שהאפליקציה מבצעת פעולות בסיכון גבוה.
AndroidX Security State היא ספריית Jetpack שמספקת גישה מאוחדת למצב האבטחה של מכשיר מבוסס-Android. הוא משלב בין ממשקי API של AOSP לבין פידים של פגיעויות ציבוריות ב-Android, כדי לספק סטטוס מקיף, מדויק ופרקטי של אבטחת המכשיר, מעבר לרמת תיקוני האבטחה (SPL).
סקירה כללית של הארכיטקטורה
בתרשים הבא מוצג איך ספריית AndroidX Security State מאחדת מאפייני פלטפורמה במכשיר, ספקי עדכונים של תקשורת בין תהליכים (IPC) ופידים ציבוריים של פגיעויות, ויוצרת מהם קבוצה אחת מגובשת של ממשקי API.

מצבים ורכיבים של תיקוני אבטחה
היתרון העיקרי בשימוש בספריית Security State הוא היכולת שלה לספק את רמת תיקוני האבטחה (SPL) ברמה מפורטת של רכיב. במהלך השנים, הוספנו ל-Android עוד מודולים לעדכוני המערכת של Google Play (פרויקט Mainline), שמתעדכנים באמצעות Google Play בנפרד מעדכוני המערכת הרגילים דרך האוויר (OTA), ומספקים תיקוני אבטחה קריטיים בתדירות שונה.
באופן דומה, למרות שרמת תיקון האבטחה בדרך כלל מחייבת את הגרסה המינימלית הנדרשת של תמונת ליבה כללית (GKI), עדכוני ליבה יכולים למעשה להקדים את לוח הזמנים של המערכת. יכול להיות שהתיקונים הספציפיים לליבת המערכת לא יופיעו במלואם במחרוזת ה-SPL הראשית של המערכת.
כדי לשפר את השקיפות, ספריית מצב האבטחה מספקת רמת תיקון אפקטיבית לכל אחד משלושת הרכיבים בנפרד:
- מערכת (
COMPONENT_SYSTEM): מייצג את מערכת ההפעלה הרגילה ואת סטטוס האבטחה של המערכת, שנגזרים משדה רמת תיקון האבטחה הרגיל. - מודולים מרכזיים של המערכת (
COMPONENT_SYSTEM_MODULES): מייצגים את סטטוס האבטחה של רכיבי המערכת המודולרית (עדכוני מערכת של Google Play), שנגזר מגרסאות ספציפיות של מודולים. - ליבה (
COMPONENT_KERNEL): מייצגת את מצב האבטחה של ליבת המכשיר, שנגזר ישירות ממחרוזת גרסת הליבה.
בהתאם לרכיב, הספרייה מספקת עד 3 מאפיינים של מידע ברמת התיקון:
- רמת תיקון האבטחה של המכשיר (DSPL): רמת התיקון הנוכחית של רכיבים ספציפיים שפועלים במכשיר, שנשלחת אליהם שאילתה באופן סינכרוני ללא בקשות רשת. תאריכים ביומן של דוחות המערכת והדוחות הראשיים (
DateBasedSecurityPatchLevel), לעומת גרסת ההפצה של הליבה (VersionedSecurityPatchLevel, לדוגמה,5.15.148). - תיקון אבטחה שפורסם (PSPL): תיקון הבסיס שפורסם באופן רשמי בעדכון האבטחה של Android ובדוחות של מסד הנתונים Open Source Vulnerabilities (OSV). האפליקציה יכולה להעריך את התאימות על ידי השוואה בין תאריכים או מחרוזות גרסה שסופקו על ידי Device SPL.
- זמינות של תיקון אבטחה (ASPL): מציין אם יש עדכונים בהמתנה במכשיר שזמינים מספקי עדכונים, שנבדקים באופן אסינכרוני באמצעות IPC. התכונה 'עדכון המערכת של Google Play' ב-Android מספקת זמינות למודולים של Mainline, ולקוחות OTA של יצרני ציוד מקורי (OEM) מספקים זמינות לעדכוני מערכת. מכיוון שעדכוני ליבה כלולים בקובץ אימג' של המערכת, הזמינות של עדכוני ליבה מוערכת באמצעות
COMPONENT_SYSTEM.
הגבלת גישה לתכונות שקשורות לאבטחה
אפשר לשלב מידע מ-Device SPL (DSPL), מ-Available SPL (ASPL) ומ-Published SPL (PSPL) כדי לקבוע באופן הקשרי את הגישה לתכונות שקשורות לאבטחה. לדוגמה, אפשר להשוות בין DSPL ל-ASPL כדי לקבוע אם יש תיקון אבטחה חדש יותר שהמשתמש עדיין לא התקין, ולבקש ממנו לעדכן לפני שהוא מתחיל פעולות רגישות כמו תשלומים או הרשמה של פרטי כניסה. אפשר גם להשתמש ב-areCvesPatched() כדי לוודא שנקודות חולשה ספציפיות בסיכון גבוה תוקנו במכשיר לפני הפעלת מערכות משנה פגיעות, למשל בדיקה של נקודות חולשה קריטיות ב-NFC או ב-Bluetooth לפני אישור תשלומים או שיתוף נתונים שמבוססים על קרבה.
שיקולים לגבי גרסת הפלטפורמה
יכולות מסוימות של מצב האבטחה תלויות בארכיטקטורת הפלטפורמה הבסיסית, והן לא זמינות בגרסאות ישנות יותר של Android:
- Android 11 (רמת API 30) ומעלה: תמיכה מלאה בכל הרכיבים, כולל שאילתות לגבי זמינות עדכונים (ASPL) וגרסאות LTS של ליבת המערכת שפורסמו בלוח המודעות.
- Android 10 (רמת API 29): תומך ברמות תיקון של המערכת ומודול המערכת, אבל גרסאות הליבה שפורסמו בלוח המודעות לא זמינות כי המעקב אחר תמונת ליבה כללית (GKI) ויעדי הליבה LTS בלוח המודעות בנושא אבטחה ב-Android התחיל ב-Android 11. עדיין אפשר לקרוא את גרסת הליבה במכשיר באופן מקומי.
- Android 9 (רמת API 28) וגרסאות קודמות: בנוסף להגבלות ב-Android 10, רכיבי מערכת מודולריים (Project Mainline) לא היו קיימים לפני Android 10.
אם רכיבי ה-SPL של מודול המערכת לא זמינים, הקריאה ל-
getDeviceSecurityPatchLevel(COMPONENT_SYSTEM_MODULES)חוזרת בבטחה לתאריך הבסיסי של ראשית זמן יוניקס (1970-01-01).
הסבר על זמינות העדכונים ועל SPL זמין (ASPL)
כדי לקבוע את מצב האבטחה של מכשיר, צריך לדעת אם יש עדכוני אבטחה בהמתנה לרכיבים ספציפיים. מכשירי Android מקבלים עדכוני אבטחה באמצעות מנגנוני מסירה שונים, כמו עדכוני מערכת OTA ועדכוני מערכת של Google Play לרכיבים מודולריים.
כדי שהאפליקציה תוכל לאחזר את ה-ASPL של רכיב מסוים, ספק העדכון המתאים צריך לפרסם את המידע הזה. כדי לתאם בין מקורות העדכונים השונים האלה, אפליקציות לקוח משתמשות בספריית AndroidX Security State כדי לשלוח שאילתות לגבי מצב האבטחה, ואילו לקוחות עדכון במכשיר משתמשים בספריית AndroidX Security State Provider הנלווית כדי לפרסם את רמת תיקון האבטחה הזמינה (ASPL).
Google מספקת מידע על עדכונים של מודולי Mainline לכל מכשירי Android עם GMS, וגם מידע על עדכוני OTA למערכת במכשירים שמשתמשים בלקוח Google OTA (GOTA).
בתרשים הבא מוצג אופן השימוש של אפליקציות לקוח בספריית AndroidX Security State כדי להריץ שאילתות לגבי מצב האבטחה גם בעדכוני מערכת Google Play וגם בעדכוני מערכת OTA:

הוספת יחסי תלות
כדי להוסיף תלות ב-AndroidX Security State, צריך לכלול את מאגר Maven של Google בפרויקט. מוסיפים את יחסי התלות לקובץ build.gradle.kts או build.gradle של האפליקציה:
Kotlin
// 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"
}
מטריצת הרשאות מוצהרות
| Target APIs | הרשאות שנדרשות ב-AndroidManifest.xml |
הערות תפעוליות |
|---|---|---|
getDeviceSecurityPatchLevel() |
ללא | קריאה סינכרונית של מאפייני מערכת מקומיים ומטא-נתונים של חבילות. |
fetchAvailableSecurityPatchLevel()queryAllAvailableUpdates() |
ללא | התקשורת מתבצעת באמצעות IPC במכשיר. הספרייה שולחת שאילתות רק לרכיבים מהימנים במכשיר (ספקי עדכונים צריכים להחזיק בהרשאה המועדפת READ_PRIVILEGED_PHONE_STATE), כך שהאפליקציה יכולה להיות בטוחה באותנטיות של המידע שהיא מקבלת. |
createVulnerabilityReportUrl()loadVulnerabilityReport()getPublishedSecurityPatchLevel()areCvesPatched()isDeviceFullyUpdated() |
android.permission.INTERNET |
נדרש כדי לאחזר דוחות OSV ציבוריים. אחרי שהנתונים נטענים לזיכרון באמצעות loadVulnerabilityReport(), שיטות השאילתות מופעלות באופן מקומי ללא גישה לרשת. |
הפעלת הספרייה
מאפיינים של SecurityPatchState עם Android Context:
Kotlin
import androidx.security.state.SecurityPatchState
val securityPatchState = SecurityPatchState(context)
Java
import androidx.security.state.SecurityPatchState;
SecurityPatchState securityPatchState = new SecurityPatchState(context);
אתחול עם context בלבד מספק גישה מיידית לרמות תיקון של מכשיר אופליין ללא תלות ברשת. (עדכון שאילתות לגבי זמינות
מתבצע באופן אסינכרוני עם ספקים במכשיר).
אם האפליקציה שלכם מעריכה את התאימות ל-CVE וכבר טענה דוח פגיעות של OSV לזיכרון, קוראי Kotlin יכולים להעביר את מחרוזת ה-JSON ישירות לבונה ב-Kotlin:
val securityPatchState = SecurityPatchState(context, vulnerabilityReportJsonString = jsonString)
ב-Java, או כשמטעינים דוחות באופן אסינכרוני אחרי ההפעלה, מאתחלים עם context וקוראים ל-securityPatchState.loadVulnerabilityReport(jsonString).
בדיקת רמות הטלאי במכשיר
שאילתה לגבי רמות הטלאי במכשיר באופן סינכרוני:
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
}
בדיקה אם יש עדכוני מערכת בהמתנה
אפליקציות יכולות להעריך את הזמינות של עדכונים בהמתנה על ידי תקשורת אסינכרונית עם ספקי עדכונים מהימנים במכשיר, בדרך כלל עדכוני מערכת של Google Play ולקוחות OTA של יצרני ציוד מקורי (OEM):
-
fetchAvailableSecurityPatchLevel(): מחזירה את ה-SPL האפקטיבי שזמין לרכיב ספציפי (אם אין עדכון חדש יותר, המערכת חוזרת ל-SPL הנוכחי של המכשיר) שאפשר להשתמש בו כדי להשוות אותו ל-SPL של המכשיר ול-SPL שפורסם. -
queryAllAvailableUpdates(): מגלה את כל ספקי העדכונים המהימנים במכשיר ומחזירUpdateCheckResultמפורט, יחד עם מטא-נתונים על המקור ועל עדכניות הנתונים.
דוגמה 1: בקשה מהמשתמשים לעדכן עדכונים בהמתנה
משתמשים ב-fetchAvailableSecurityPatchLevel() כדי להציג למשתמשים הודעה כשעדכוני אבטחה זמינים (לדוגמה, על ידי הפעלת 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
ב-Java, שיטות אסינכרוניות מחזירות ListenableFuture ומנתבות קריאות חוזרות באמצעות 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));
דוגמה 2: בדיקת הסטטוס המפורט של ספק
אפשר להשתמש ב-queryAllAvailableUpdates() כדי לבדוק ספקים ספציפיים, חותמות זמן ורשומות של 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));
אימות הפתרון של נקודת החולשה ובדיקת CVE
כדי להעריך את אמצעי ההגנה מפני CVE, לבדוק את התאימות הכוללת לעדכונים או לבדוק את רמות תיקוני האבטחה שפורסמו (PSPL), האפליקציה צריכה קודם לקבל ולטעון דוח פגיעויות של OSV, כפי שמפורט במאמרי העזרה של ה-API של 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);
טעינת דוחות על נקודות חולשה
- שמירה במטמון מקומי ורענון באמצעות WorkManager: מאחר שפרסומי האבטחה של Android מתפרסמים מדי חודש, צריך לשמור במטמון את קובץ ה-JSON שהורד באחסון הפנימי (
context.filesDir) ולתזמן משימת רקע תקופתית באמצעותWorkManager(רצוי כל 24 עד 48 שעות) כדי לרענן את הדוח, ולקרוא מהמטמון המקומי באופן סינכרוני בהפעלת האפליקציה. - Background Threading: מפעילים את
loadVulnerabilityReport()ב-thread ברקע (Dispatchers.IOב-Kotlin אוExecutorב-Java) כדי למנוע חסימה של שרשור ה-UI הראשי בזמן ניתוח רשומות CVE. - הערכה של LTS של ליבת המערכת: קריאה ל-
getPatchedCves(COMPONENT_KERNEL, ...)מפעילה אתIllegalArgumentException, ו-areCvesPatched()לא מעריך את ה-CVE של ליבת המערכת. במקום זאת, כדי להעריך את אבטחת הליבה, משווים את גרסת הליבה של המכשיר ליעדי ה-LTS של ליבת Android הנפוצה שמוחזרים על ידיgetPublishedSecurityPatchLevel(COMPONENT_KERNEL)בהתאם לענף הראשי והמשני שלה (לדוגמה, השוואה בין ליבת5.15.140לבין יעד5.15.159).
מקורות מידע נוספים
מידע נוסף על מצב האבטחה של המכשיר זמין במקורות המידע הבאים:
מאמרי עזרה
- חדשות האבטחה של Android
- רכיבים מודולריים של המערכת
- תמונת ליבה גנרית (GKI)
- תיקוני אבטחה משלימים
- Play Integrity API
- מסד הנתונים של Open Source Vulnerabilities (OSV)
- נתוני גרסה 1.1.0 של Security State