קטגוריה ב-OWASP: MASVS-PLATFORM: Platform Interaction
סקירה כללית
גשר מקורי, שנקרא לפעמים גשר JavaScript, הוא מנגנון שמקל על התקשורת בין WebView לבין קוד מקורי של Android. כדי להשתמש בו, צריך להשתמש בשיטה addJavascriptInterface. היא מאפשרת תקשורת דו-כיוונית בין קוד JavaScript שפועל ב-WebView לבין קוד Java של אפליקציית Android. השיטה addJavascriptInterface חושפת אובייקט Java לכל המסגרות של WebView, וכל מסגרת יכולה לגשת לשם האובייקט ולקרוא לשיטות שלו. עם זאת, אין מנגנון באפליקציה שמאפשר לאמת את המקור של המסגרת שקוראת בתוך WebView, ולכן יש חששות לגבי אבטחה כי מהימנות התוכן לא ברורה.
אפשר גם להטמיע גשר מקורי עם ערוצי הודעות HTML באמצעות WebViewCompat.postWebMessage או WebMessagePort.postMessage של Android כדי לתקשר עם Window.postMessage של JavaScript. WebViewCompat.postWebMessage ו-WebMessagePort.postMessage יכולים לקבל הודעות JavaScript שנשלחות דרך Window.postMessage, שיופעלו ב-WebView.
יש כמה סיכונים שקשורים לגשרים מקוריים:
- גשרים מבוססי JavascriptInterface:
- השיטה
addJavascriptInterfaceמחדירה אובייקט Java שסופק לכל פריים ב-WebView, כולל iframe, מה שאומר שהיא חשופה להתקפה של צדדים שלישיים זדוניים שמחדירים פריים לאתר לגיטימי. אפליקציות שמיועדות לרמת API 16 או לגרסאות קודמות נמצאות בסיכון גבוה במיוחד להתקפה, כי אפשר להשתמש בשיטה הזו כדי לאפשר ל-JavaScript לשלוט באפליקציית המארח. - שיקוף של תוכן שסופק על ידי משתמשים לא מהימנים ב-WebView עם הפעלת גשר מקורי מאפשר פרצת אבטחה XSS (cross-site scripting).
- השיטה
- גשרים שמבוססים על MessageChannel:
- היעדר בדיקות מקור בנקודות הקצה של ערוץ ההודעות אומר שהודעות יתקבלו מכל שולח, כולל הודעות שמכילות קוד זדוני.
- יכול להיות ש-Java ייחשף בטעות ל-JavaScript אקראי.
השפעה
גורמים זדוניים יכולים לנצל את השיטות addJavascriptInterface, postWebMessage ו-postMessage כדי לגשת ל-WebView, לתפעל אותו או להחדיר אליו קוד שהם שולטים בו. הדבר עלול להוביל להפניה של משתמשים לאתרים זדוניים, לטעינה של תוכן זדוני או להרצה של קוד זדוני במכשירים שלהם, שיכול לחלץ מידע אישי רגיש או להשיג הסלמת הרשאות (privilege escalation).
סיכון: סיכונים של addJavascriptInterface
רכיב WebView מטמיע פונקציות בסיסיות של דפדפן, כמו עיבוד דפים, ניווט וביצוע JavaScript. אפשר להשתמש ב-WebView בתוך אפליקציה כדי להציג תוכן מהאינטרנט כחלק מפריסת הפעילות. הטמעה של גשר מקורי ב-WebView באמצעות השיטה addJavascriptInterface עלולה ליצור בעיות אבטחה כמו פרצת אבטחה XSS (cross-site scripting), או לאפשר לתוקפים לטעון תוכן לא מהימן באמצעות הזרקת ממשק ולשנות את אפליקציית המארח בדרכים לא רצויות, ולהריץ קוד Java עם ההרשאות של אפליקציית המארח.
אמצעי צמצום סיכונים
השבתה של JavaScript
בתרחישים שבהם WebView לא דורש JavaScript, אל תקראו ל-setJavaScriptEnabled בתוך WebSettings (לדוגמה, בזמן הצגת תוכן HTML סטטי). כברירת מחדל, ההרצה של JavaScript מושבתת ב-WebView.
הסרת ממשק JavaScript כשנטען תוכן לא מהימן
מוודאים שאובייקטים מממשק ה-JavaScript מוסרים על ידי קריאה ל-removeJavascriptInterface לפני שרכיב ה-WebView טוען תוכן לא מהימן. לדוגמה, אפשר לעשות זאת בקריאה ל-shouldInterceptRequest.
Kotlin
webView.removeJavascriptInterface("myObject")
Java
webView.removeJavascriptInterface("myObject");
טעינה של תוכן מהאינטרנט רק דרך HTTPS
אם אתם צריכים לטעון תוכן לא מהימן, צריך לוודא ש-WebView טוען תוכן מהאינטרנט באמצעות חיבור מוצפן (אפשר לעיין גם בהנחיות שלנו בנושא תקשורת בטקסט לא מוצפן). כדי למנוע את טעינת הדף הראשונית בחיבורים לא מוצפנים, צריך להגדיר את android:usesCleartextTraffic לערך false בקובץ AndroidManifest או לאסור תעבורת נתונים של HTTP בתצורה של אבטחת רשת. מידע נוסף זמין בusesCleartextTraffic.
Xml
<application
android:usesCleartextTraffic="false">
<!-- Other application elements -->
</application>
כדי לוודא שלא מתבצעות הפניות אוטומטיות וגלישה נוספת באפליקציה בתעבורה לא מוצפנת, צריך לבדוק את סכימת ה-HTTP ב-loadUrl או ב-shouldInterceptRequest:
Kotlin
fun loadSecureUrl(webView: WebView?, url: String?) {
webView?.let { wv -> // Ensure valid WebView and URL
url?.let {
try {
val uri = URI(url)
if (uri.scheme.equals("https", ignoreCase = true)) { // Enforce HTTPS scheme for security
wv.loadUrl(url)
} else {
// Log an error or handle the case where the URL is not secure
System.err.println("Attempted to load a non-HTTPS URL: $url")
}
} catch (e: Exception) {
// Handle exception for improper URL format
System.err.println("Invalid URL syntax: $url")
}
}
}
}
Java
public void loadSecureUrl(WebView webView, String url) {
if (webView != null && url != null) { // Ensure valid WebView and URL
try {
URI uri = new URI(url);
String scheme = uri.getScheme();
if ("https".equalsIgnoreCase(scheme)) { // Enforce HTTPS scheme for security
webView.loadUrl(url);
} else {
// Log an error or handle the case where the URL is not secure
System.err.println("Attempted to load a non-HTTPS URL: " + url);
}
} catch (URISyntaxException e) {
// Handle exception for improper URL format
System.err.println("Invalid URL syntax: " + url);
}
}
}
אימות תוכן לא מהימן
אם קישורים חיצוניים נטענים ב-WebView, צריך לאמת גם את הסכימה וגם את המארח (דומיינים ברשימת ההיתרים). דומיינים שלא מופיעים ברשימת הדומיינים המורשים צריכים להיפתח בדפדפן ברירת המחדל.
לא לטעון תוכן לא מהימן
אם אפשר, טוענים ל-WebView רק כתובות URL ותוכן שנמצאים בבעלות מפתח האפליקציה.
לא לחשוף מידע אישי רגיש
אם האפליקציה שלכם ניגשת למידע אישי רגיש באמצעות WebView, כדאי להשתמש בשיטה clearCache כדי למחוק קבצים שנשמרו באופן מקומי, לפני שמשתמשים בממשק JavaScript. אפשר גם להשתמש בכותרות בצד השרת, כמו no-store, כדי לציין שאפליקציה לא צריכה לשמור במטמון תוכן מסוים.
לא לחשוף פונקציות רגישות
אם האפליקציה שלכם דורשת הרשאת גישה למידע רגיש או אוספת מידע אישי רגיש, עליכם לוודא שהיא נקראת מתוך קוד באפליקציה ושהמשתמשים מקבלים גילוי נאות במקום בולט. מומלץ להימנע משימוש בממשקי JavaScript לביצוע פעולות רגישות או לגישה לנתוני משתמשים.
רמת ה-API לטירגוט היא 21 ומעלה
דרך מאובטחת אחת להשתמש בשיטה addJavascriptInterface היא לטרגט רמת API 21 ומעלה, על ידי הקפדה על כך שהשיטה תופעל רק כשמריצים אותה ברמת API 21 ומעלה. לפני API 21, JavaScript יכול היה להשתמש בהשתקפות כדי לגשת לשדות הציבוריים של אובייקט מוזרק.
סיכון: סיכונים ב-MessageChannel
היעדר בקרת מקור ב-postWebMessage() וב-postMessage() עלול לאפשר לתוקפים ליירט הודעות או לשלוח הודעות לטיפול מקומי.
אמצעי צמצום סיכונים
כשמגדירים את postWebMessage() או postMessage(), צריך לאשר רק הודעות מדומיינים מהימנים. כדי לעשות זאת, לא משתמשים ב- * כמקור היעד, אלא מציינים במפורש את הדומיין שממנו צפויים לשלוח את ההודעות.
משאבים
- שיטות מומלצות לשימוש ב-postMessage()
- מאמרי עזרה בנושא addJavascriptInterface
- מסמכי תיעוד בנושא postMessage()
- מסמכי תיעוד בנושא WebMessagePort.postMessage()
- תיעוד של WebViewClient.shouldInterceptRequest
- תיעוד של עצות אבטחה בנוגע ל-addJavascriptInterface
- חומרי עזר בנושא clearCache
- removeJavascript documentation
- הפעלת JavaScript ברכיבי WebView