רמת האבטחה של האפליקציה שלכם שווה לזו של מערכת ההפעלה הבסיסית שלה. כדי לצמצם את הסיכון, האפליקציה צריכה להגביל פעולות שקשורות לאבטחה באמצעות הערכה בזמן אמת של מצב האבטחה במכשיר. ההערכה הזו קובעת אם המכשיר, ובמיוחד רכיבי הליבה של המערכת, מעודכן באופן מלא ומוגן מפני נקודות חולשה שפורסמו בחדשות האבטחה של 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): רמת התיקון הנוכחית של רכיבים נפרדים שפועלים במכשיר, שנשלפת באופן סינכרוני ללא בקשות לרשת. תאריכי היומן של דוחות המערכת וה-Mainline (
DateBasedSecurityPatchLevel), ואילו הליבה מדווחת על גרסת הפרסום שלה (VersionedSecurityPatchLevel, לדוגמה,5.15.148). - רמת תיקון האבטחה שפורסמה (PSPL): רמת הבסיס שפורסמה באופן רשמי בעדכון האבטחה הדחוף של Android ובדוחות של מסד הנתונים Open Source Vulnerabilities (OSV). האפליקציה יכולה להעריך את התאימות על ידי השוואה בין תאריכים או מחרוזות גרסה שסופקו על ידי Device SPL.
- זמינות של תיקון אבטחה (ASPL): מציין אם יש עדכונים בהמתנה במכשיר שזמינים מספקי עדכונים, שנבדקים באופן אסינכרוני באמצעות IPC. התכונה 'עדכון המערכת של Google Play' ב-Android מספקת זמינות למודולים של Mainline, ולקוחות OTA של יצרני ציוד מקורי מספקים זמינות לעדכוני מערכת. מכיוון שעדכוני ליבה כלולים בקובץ אימג' של המערכת, הזמינות של עדכוני ליבה מוערכת באמצעות
COMPONENT_SYSTEM.
הגבלת גישה לתכונות שקשורות לאבטחה
אפשר לשלב מידע מ-Device SPL (DSPL), מ-Available SPL (ASPL) ומ-Published SPL (PSPL) כדי לקבוע באופן הקשרי את הגישה לתכונות שקשורות לאבטחה. לדוגמה, אפשר להשוות בין DSPL לבין ASPL כדי לקבוע אם יש טלאי אבטחה חדש יותר שהמשתמש עדיין לא התקין, ולבקש ממנו לעדכן לפני שהוא מתחיל פעולות רגישות כמו תשלומים או הרשמה של פרטי כניסה. אפשר גם להשתמש ב-areCvesPatched() כדי לוודא שנקודות חולשה ספציפיות בסיכון גבוה תוקנו במכשיר לפני הפעלת מערכות משנה פגיעות, למשל בדיקה של נקודות חולשה קריטיות ב-NFC או ב-Bluetooth לפני אישור תשלומים או שיתוף נתונים שמבוססים על קרבה.
שיקולים לגבי גרסת הפלטפורמה
יכולות מסוימות של מצב האבטחה תלויות בארכיטקטורת הפלטפורמה הבסיסית, והן לא זמינות בגרסאות ישנות יותר של Android:
- Android 11 (רמת API 30) ומעלה: תמיכה מלאה בכל הרכיבים, כולל גרסאות LTS של ליבת המערכת שפורסמו בלוח המודעות ושאילתות לגבי זמינות עדכונים (ASPL).
- Android 10 (רמת API 29): תומך ברמות תיקון של המערכת ומודול המערכת, אבל גרסאות הליבה שפורסמו ב-Bulletin לא זמינות כי מעקב אחר Generic Kernel Image (GKI) ויעדי LTS של הליבה ב-Android Security Bulletin התחיל ב-Android 11. עדיין אפשר לקרוא את גרסת הליבה במכשיר באופן מקומי.
- Android 9 (רמת API 28) וגרסאות קודמות: בנוסף למגבלות של Android 10, רכיבי מערכת מודולריים (Project Mainline) לא היו קיימים לפני Android 10.
אם תיקוני האבטחה של מודול המערכת לא זמינים, הפונקציה
getDeviceSecurityPatchLevel(COMPONENT_SYSTEM_MODULES)חוזרת בבטחה לתאריך הבסיסי של ראשית זמן יוניקס (1970-01-01).
הסבר על זמינות עדכונים ועל תיקון אבטחה זמין (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"
}
מטריצת ההרשאות המוצהרות
| ממשקי API של יעד | ההרשאות הנדרשות ב-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. - הערכה של Kernel 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