WebView – גשרים מקומיים

קטגוריה ב-OWASP: MASVS-PLATFORM: Platform Interaction

סקירה כללית

גשר מקורי, שנקרא לפעמים 'גשר JavaScript', הוא מנגנון שמאפשר תקשורת בין WebView לבין קוד Android נייטיב, באמצעות באמצעות השיטה addJavascriptInterface. כך אפשר תקשורת בין קוד JavaScript שפועל ב-WebView לבין Android בקוד Java של האפליקציה. השיטה addJavascriptInterface חושפת Java לכל המסגרות של WebView, וכל מסגרת יכולה לגשת לשם האובייקט. ולמידע על שיטות הקריאה. עם זאת, אין לאפליקציה מנגנון לאימות המקור של המסגרת הקוראת ב-WebView, מה שעלול לעורר חששות אבטחה כי לא ניתן לקבוע בוודאות את מהימנות התוכן.

ניתן גם להטמיע גשר מקורי באמצעות ערוצי הודעות HTML באמצעות WebViewCompat.postWebMessage של Android או WebMessagePort.postMessage כדי לתקשר עם JavaScript Window.postMessage. WebViewCompat.postWebMessage והקבוצה WebMessagePort.postMessage יכול לקבל הודעות JavaScript שנשלחות באמצעות Window.postMessage שיופעל בתוך ה-WebView.

יש מספר סיכונים הקשורים לגשרים מקומיים:

  • גשרים שמבוססים על JavascriptInterface:
    • ה-method addJavascriptInterface מחדירה אובייקט Java שסופק כל מסגרת ב-WebView, כולל iframes, כלומר חשופים מתקפה על ידי צדדים שלישיים זדוניים שמחדירים פריימים לאתר לגיטימי. אפליקציות שמטרגטות לרמת API 16 או גרסאות קודמות נמצאות בסיכון גבוה במיוחד מתקפה כי השיטה הזו יכולה לשמש כדי לאפשר ל-JavaScript לשלוט במארח תרגום מכונה.
    • ייצוג של תוכן לא מהימן שהמשתמשים סיפקו ברכיבי WebView מותאמים לגשר שמאפשר התקפות חוצות-אתרים (cross-site scripting) (XSS).
  • גשרים מבוססי-ערוץ Message:
    • אם אין בדיקות מקור בנקודות הקצה של ערוץ ההודעות, ההודעות להתקבל מכל שולח, כולל משתמשים שמכילים קוד זדוני.
    • יכול להיות ש-Java תהיה חשופה בטעות ל-JavaScript שרירותי.

השפעה

גורמים זדוניים יכולים להשתמש בשיטות addJavascriptInterface,‏ postWebMessage ו-postMessage כדי לגשת ל-WebView, לבצע בו מניפולציות או להחדיר אליו קוד שהם שולטים בו. כתוצאה מכך, המשתמשים עשויים להופנות לאתרים זדוניים, לטעון תוכן זדוני או להפעיל במכשירים שלהם קוד זדוני שיכול לחלץ מידע רגיש או להוביל להסלמת הרשאות.

סיכון: סיכוני addJavaScriptInterface

רכיב WebView מיישם פונקציות בסיסיות של הדפדפן, כמו עיבוד דפים, בניווט ובביצוע של JavaScript. ניתן להשתמש ב-WebView בתוך אפליקציה כדי להציג תוכן מהאינטרנט כחלק מפריסת פעילות. הטמעת גשר מקומי ב-WebView באמצעות השיטה addJavascriptInterface עלולה לגרום לבעיות אבטחה כמו סקריפטים חוצי-אתרים (XSS), או לאפשר לתוקפים לטעון תוכן לא מהימן באמצעות הזרקת ממשק ולבצע מניפולציות באפליקציית המארח בדרכים לא רצויות, ולהריץ קוד Java עם ההרשאות של אפליקציית המארח.

מיטיגציות

השבתת JavaScript

בתרחישים שבהם רכיב ה-WebView לא דורש JavaScript, אל תפעילו את setJavaScriptEnabled בתוך WebSettings (לדוגמה, בזמן הצגת תוכן HTML סטטי). כברירת מחדל, ההרצה של JavaScript מושבתת ב-WebView.

הסרת ממשק JavaScript בזמן טעינת תוכן לא מהימן

כדי לוודא שהאובייקטים יוסרו מממשק ה-JavaScript, צריך לבצע קריאה ל-removeJavascriptInterface לפני שרכיב ה-WebView יטען תוכן לא מהימן. לדוגמה, אפשר לעשות זאת בקריאה ל-shouldInterceptRequest.

Kotlin

webView.removeJavascriptInterface("myObject")

Java

webView.removeJavascriptInterface("myObject");

טעינת תוכן מהאינטרנט רק דרך HTTPS

אם צריך לטעון תוכן לא מהימן, מוודאים שה-WebView טוען תוכן אינטרנט באמצעות חיבור מוצפן (אפשר לעיין גם בהנחיות שלנו לגבי Cleartext תקשורת). כדי למנוע את הטעינה הראשונית של הדף בחיבור ללא הצפנה, מגדירים את 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, מומלץ להשתמש ב-method‏ clearCache כדי למחוק את כל הקבצים ששמורים באופן מקומי, לפני שמשתמשים בממשק JavaScript. אפשר גם להשתמש בכותרות בצד השרת, כמו No-store, כדי לציין שאפליקציה לא צריכה לשמור תוכן מסוים במטמון.

לא לחשוף פונקציות רגישות

אם האפליקציה דורשת הרשאות רגישות או אוספת מידע אישי רגיש, לוודא קריאה מתוך הקוד בתוך האפליקציה, ושהקריאה מוצג למשתמשים. להימנע משימוש בממשקי JavaScript פעולות רגישות או נתוני משתמשים.

רמת ה-API לטירגוט צריכה להיות 21 ומעלה

אחת מהדרכים המאובטחות להשתמש ב-method addJavascriptInterface היא לטרגט את רמת ה-API 21 ואילך, כי מוודאים שה-method מופעלת רק כשמריצים את השיטה ברמת API 21 ומעלה. לפני API 21, JavaScript יכול היה להשתמש בהשתקפות כדי לגשת לשדות הציבוריים של אובייקט שהוזן.


סיכון: סיכונים של MessageChannel

היעדר בקרת מקורות ב-postWebMessage() וב-postMessage() עלול לאפשר תוקפים כדי ליירט הודעות או לשלוח הודעות לרכיבי handler מקוריים.

מיטיגציות

כשמגדירים את postWebMessage() או postMessage(), מותר לאפשר רק הודעות מאת בדומיינים מהימנים על ידי הימנעות משימוש ב-* כמקור היעד, ובמקום זאת לציין במפורש את הדומיין השולח הצפוי.


משאבים