קטגוריה של OWASP: MASVS-STORAGE: אחסון
סקירה כללית
במסמך הזה מתוארות כמה בעיות שקשורות להכללת קבצים, ומוצעים פתרונות דומים לכולן. הבעיות האלה מתמקדות בפרצות אבטחה שנובעות מגישה לקבצים בתוך רכיבי WebView, וכוללות מפרצות מסוכנות WebSettings שמאפשרות גישה לקבצים או הפעלה של JavaScript, ועד לשיטה של WebKit שיוצרת בקשה לבחירת קבצים. המסמך הזה יכול לעזור לכם אם אתם מחפשים הנחיות לפתרון בעיות ב-WebView שנובעות משימוש בסכימת file://, מגישה בלתי מוגבלת לקבצים מקומיים ומפרצת אבטחה XSS (cross-site scripting).
באופן יותר ספציפי, במסמך הזה מפורטים הנושאים הבאים:
-
WebSettingsהיא מחלקה שמכילה שיטות לניהול מצבי ההגדרה של WebViews. השיטות האלה יכולות לפתוח תצוגות WebView למתקפות שונות, שיפורטו בהמשך. במסמך הזה נסביר על השיטות שקשורות לגישה לקבצים, ועל ההגדרה שמאפשרת להריץ JavaScript: - אפשר להשתמש בשיטות
setAllowFileAccess,setAllowFileAccessFromFileURLsו-setAllowUniversalAccessFromFileURLsכדי להעניק גישה לקבצים מקומיים באמצעות כתובת URL של סכימת קבצים (file://). עם זאת, סקריפטים זדוניים יכולים לנצל את השיטות האלה כדי לגשת לקבצים מקומיים שרירותיים שהאפליקציה יכולה לגשת אליהם, כמו תיקיית/data/משלה. לכן, השיטות האלה סומנו כלא מאובטחות והוצאו משימוש ב-API 30 לטובת חלופות בטוחות יותר, כמוWebViewAssetLoader. - אפשר להשתמש בשיטה
setJavascriptEnabledכדי להפעיל את ההרצה של JavaScript בתוך WebViews. כך האפליקציות חשופות לפרצת אבטחה מסוג XSS שמבוססת על קבצים. במיוחד אם ההגדרה מאפשרת טעינה של קבצים מקומיים או של תוכן אינטרנט לא מהימן שעשוי להכיל קוד הפעלה, אם ההגדרה מאפשרת גישה לקבצים שאפשר ליצור או לשנות ממקורות חיצוניים, או אם ההגדרה מאפשרת לרכיבי WebView להפעיל JavaScript, המשתמשים והנתונים שלהם נמצאים בסיכון. -
WebChromeClient.onShowFileChooserהיא שיטה ששייכת לחבילהandroid.webkit, שמספקת כלים לגלישה באינטרנט. אפשר להשתמש בשיטה הזו כדי לאפשר למשתמשים לבחור קבצים ב-WebView. עם זאת, אפשר לנצל לרעה את התכונה הזו כי ב-WebViews לא נאכפות הגבלות על הקובץ שנבחר.
השפעה
ההשפעה של הכללת קבצים יכולה להיות תלויה בהגדרות WebSettings שמוגדרות ב-WebView. הרשאות לקבצים רחבות מדי עלולות לאפשר לתוקפים לגשת לקבצים מקומיים ולגנוב מידע אישי רגיש, פרטים אישיים מזהים (PII) או נתוני האפליקציה הפרטיים. הפעלת JavaScript יכולה לאפשר לתוקפים להריץ JavaScript ב-WebView או במכשיר של משתמש. קבצים שנבחרו באמצעות השיטה onShowFileChooser עלולים לסכן את אבטחת המשתמשים, כי אין דרך לוודא שהמקור של הקובץ מהימן באמצעות השיטה או WebView.
סיכון: גישה מסוכנת לקבצים דרך file://
הפעלת ההגדרות setAllowFileAccess, setAllowFileAccessFromFileURLs ו-setAllowUniversalAccessFromFileURLs עלולה לאפשר לכוונות זדוניות ולבקשות WebView עם הקשר file:// לגשת לקבצים מקומיים שרירותיים, כולל קובצי Cookie של WebView ונתונים פרטיים של האפליקציה. בנוסף, שימוש בשיטה onShowFileChooser
יכול לאפשר למשתמשים לבחור ולהוריד קבצים ממקורות לא מהימנים.
כל השיטות האלה עלולות להוביל להוצאת פרטים אישיים מזהים (PII), פרטי כניסה או מידע אישי רגיש אחר, בהתאם להגדרת האפליקציה.
אמצעי צמצום סיכונים
אימות כתובות ה-URL של הקבצים
אם האפליקציה שלכם דורשת גישה לקבצים דרך file:// כתובות URL, חשוב להוסיף לרשימת ההיתרים רק כתובות URL ספציפיות שידוע שהן לגיטימיות, כדי להימנע משגיאות נפוצות.
שימוש ב-WebViewAssetLoader
במקום השיטות שצוינו, צריך להשתמש ב-WebViewAssetLoader. השיטה הזו משתמשת בסכימת http(s)//: במקום בסכימת file:// כדי לגשת לנכסים במערכת הקבצים המקומית, והיא לא פגיעה להתקפה שמתוארת כאן.
Kotlin
val assetLoader: WebViewAssetLoader = Builder()
.addPathHandler("/assets/", AssetsPathHandler(this))
.build()
webView.setWebViewClient(object : WebViewClientCompat() {
@RequiresApi(21)
override fun shouldInterceptRequest(view: WebView?, request: WebResourceRequest): WebResourceResponse {
return assetLoader.shouldInterceptRequest(request.url)
}
@Suppress("deprecation") // for API < 21
override fun shouldInterceptRequest(view: WebView?, url: String?): WebResourceResponse {
return assetLoader.shouldInterceptRequest(Uri.parse(url))
}
})
val webViewSettings: WebSettings = webView.getSettings()
// Setting this off for security. Off by default for SDK versions >= 16.
webViewSettings.allowFileAccessFromFileURLs = false
// Off by default, deprecated for SDK versions >= 30.
webViewSettings.allowUniversalAccessFromFileURLs = false
// Keeping these off is less critical but still a good idea, especially if your app is not
// using file:// or content:// URLs.
webViewSettings.allowFileAccess = false
webViewSettings.allowContentAccess = false
// Assets are hosted under http(s)://appassets.androidplatform.net/assets/... .
// If the application's assets are in the "main/assets" folder this will read the file
// from "main/assets/www/index.html" and load it as if it were hosted on:
// https://appassets.androidplatform.net/assets/www/index.html
webView.loadUrl("https://appassets.androidplatform.net/assets/www/index.html")
Java
final WebViewAssetLoader assetLoader = new WebViewAssetLoader.Builder()
.addPathHandler("/assets/", new AssetsPathHandler(this))
.build();
webView.setWebViewClient(new WebViewClientCompat() {
@Override
@RequiresApi(21)
public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {
return assetLoader.shouldInterceptRequest(request.getUrl());
}
@Override
@SuppressWarnings("deprecation") // for API < 21
public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
return assetLoader.shouldInterceptRequest(Uri.parse(url));
}
});
WebSettings webViewSettings = webView.getSettings();
// Setting this off for security. Off by default for SDK versions >= 16.
webViewSettings.setAllowFileAccessFromFileURLs(false);
// Off by default, deprecated for SDK versions >= 30.
webViewSettings.setAllowUniversalAccessFromFileURLs(false);
// Keeping these off is less critical but still a good idea, especially if your app is not
// using file:// or content:// URLs.
webViewSettings.setAllowFileAccess(false);
webViewSettings.setAllowContentAccess(false);
// Assets are hosted under http(s)://appassets.androidplatform.net/assets/... .
// If the application's assets are in the "main/assets" folder this will read the file
// from "main/assets/www/index.html" and load it as if it were hosted on:
// https://appassets.androidplatform.net/assets/www/index.html
webview.loadUrl("https://appassets.androidplatform.net/assets/www/index.html");
השבתה של שיטות מסוכנות ב-WebSettings
ערך ברירת המחדל של השיטה setAllowFileAccess() הוא TRUE ב-API ברמה 29 ומטה, ו-FALSE ב-API ברמה 30 ומעלה. שיטות setAllowFileAccessFromFileURLs() ו-setAllowUniversalAccessFromFileURLs() מוגדרות כברירת מחדל ל-FALSE ברמת API 16 ואילך. (ערכי ברירת המחדל האלה השתנו ברמת API 16 כדי לאכוף אבטחה מחמירה יותר על ידי הגבלת הגישה לקבצים מקומיים מאותו מקור, וכך להגן על אפליקציות מפני פרצת אבטחה XSS (cross-site scripting) וגישה לא מורשית לקבצים).
אם יש צורך להגדיר WebSettings אחרים, מומלץ להשבית באופן מפורש את השיטות האלה, במיוחד באפליקציות שמטרגטות רמות API שקטנות מ-29 או שוות להן.
סיכון: XSS שמבוסס על קבצים
הגדרת השיטה setJavacriptEnabled ל-TRUE מאפשרת להריץ JavaScript בתוך WebView, ובשילוב עם גישה לקבצים שמופעלת כמו שמתואר למעלה, אפשר לבצע XSS מבוסס-קבצים באמצעות הרצת קוד בתוך קבצים שרירותיים או אתרים זדוניים שנפתחים בתוך WebView.
אמצעי צמצום סיכונים
מניעת טעינה של קבצים מקומיים ברכיבי WebView
כמו בסיכון הקודם, אפשר להימנע מ-XSS שמבוסס על קבצים אם הערכים של setAllowFileAccess(), setAllowFileAccessFromFileURLs() ו-setAllowUniversalAccessFromFileURLs() מוגדרים ל-FALSE.
מניעת הרצה של JavaScript ברכיבי WebView
מגדירים את ה-method setJavascriptEnabled ל-FALSE כדי ש-JavaScript לא יוכל לפעול ב-WebViews.
מוודאים שרכיבי WebView לא טוענים תוכן לא מהימן
לפעמים יש צורך להפעיל את ההגדרות האלה ב-WebView. במקרה כזה, חשוב לוודא שנטען רק תוכן מהימן. דרך טובה לוודא שהתוכן מהימן היא להגביל את ההרצה של JavaScript רק למה שאתם שולטים בו, ולא לאפשר JavaScript שרירותי. אחרת,
מניעה של טעינת תנועת HTTP לא מוצפנת מבטיחה שרכיבי WebView עם
הגדרות מסוכנות לפחות לא יוכלו לטעון כתובות URL של HTTP. אפשר לעשות זאת
באמצעות המניפסט, על ידי הגדרת android:usesCleartextTraffic לערך
False, או על ידי הגדרת Network Security Config שמונעת תנועת HTTP.
משאבים
- דף הפניית ה-API setAllowUniversalAccessFromFileURLs
- דף הפניית API של setAllowFileAccessFromFileURLs
- דף הפניית API של WebViewAssetLoader
- מסמכי תיעוד של CodeQL
- הבלוג של Oversecured
- בדף ההפניה בנושא onShowFileChooser