תצוגות אינטרנט – טעינת URI לא בטוחה
קל לארגן דפים בעזרת אוספים
אפשר לשמור ולסווג תוכן על סמך ההעדפות שלך.
קטגוריית OWASP: MASVS-CODE: איכות הקוד
סקירה כללית
טעינה של URI לא בטוח מתרחשת כשאפליקציית Android לא מצליחה להעריך בצורה נכונה את התוקף של URI לפני שהיא טוענת אותו ל-WebView.
הסיבה הבסיסית לפגיעות מסוג זה היא שURI מורכב מכמה חלקים, שלפחות הסכימה והמארח (של חלק הרשות) צריכים לעבור אימות (למשל, להיכלל ברשימת ההיתרים) לפני ש-URI נטען ל-WebView או לפני שהאפליקציה משתמשת בו באופן פנימי.
הטעויות הנפוצות ביותר הן:
- הבדיקה מתבצעת רק לגבי המארח ולא לגבי הסכימה, ולכן תוקף יכול להשתמש בסכימות כמו
http://
, content://
או javascript://
עם מארח מאומת.
- הניתוח של ה-URI נכשל, במיוחד במקרים שבהם ה-URI מתקבל כמחרוזת.
- אימות הסכימה אבל לא המארח (אימות מארח לא מספיק).
במקרה האחרון, זה קורה בדרך כלל כשהאפליקציה צריכה לאפשר תתי-דומיינים שרירותיים של דומיין ראשי. לכן, גם אם שם המארח חולץ בצורה נכונה, האפליקציה משתמשת בשיטות כמו startsWith
, endsWith,
או contains
של המחלקה java.lang.String
כדי לאמת את הנוכחות של דומיין ראשי בקטע המחרוזת שחולץ. שימוש לא נכון בשיטות האלה עלול להוביל לתוצאות שגויות ולגרום לאפליקציה לבטוח באופן לא תקין במארח שעלול להיות זדוני.
השפעה
ההשפעה יכולה להיות שונה בהתאם להקשר שבו נעשה שימוש במארח. במקרים שבהם טעינה של מזהה URI זדוני (כלומר, כזה שעקף סינון או רשימת היתרים) ב-WebView עלולה להוביל להשתלטות על חשבון (למשל, באמצעות פישינג), להרצת קוד (למשל, טעינה של JavaScript זדוני) או לפריצה למכשיר (קוד ניצול שנמסר באמצעות היפר-קישור).
אמצעי צמצום סיכונים
כשמטפלים במזהי URI של מחרוזות, חשוב לנתח את המחרוזת כמזהה URI ולאמת את הסכימה ואת המארח:
Kotlin
fun isUriTrusted(incomingUri: String, trustedHostName: String): Boolean {
try {
val uri = Uri.parse(incomingUri)
return uri.scheme == "https" && uri.host == trustedHostName
} catch (e: NullPointerException) {
throw NullPointerException("incomingUri is null or not well-formed")
}
}
Java
public static boolean isUriTrusted(String incomingUri, String trustedHostName)
throws NullPointerException {
try {
Uri uri = Uri.parse(incomingUri);
return uri.getScheme().equals("https") &&
uri.getHost().equals(trustedHostName);
} catch (NullPointerException e) {
throw new NullPointerException(
"incomingUri is null or not well-formed");
}
}
באימות מארח, אחרי שמבודדים את החלק המתאים ב-URI, חשוב לאמת אותו באופן מלא (ולא חלקי) כדי לזהות בצורה מדויקת אם המארח מהימן או לא. כשמשתמשים בשיטות כמו startsWith
או endsWith
, חשוב להשתמש בתחביר הנכון ולא להתעלם מתווים או מסמלים נדרשים (לדוגמה, בשיטה endsWith
נדרש התו '.
' לפני שם הדומיין כדי לקבל התאמה מדויקת). התעלמות מהתווים האלה עלולה להוביל להתאמות לא מדויקות ולפגוע באבטחה. מכיוון שאפשר להוסיף אינסוף רמות של קינון לדומיינים משניים, התאמה של ביטויים רגולריים היא לא שיטה מומלצת לאימות של שמות מארחים.
תורמים: Dimitrios Valsamaras ו-Michael Peck מ-Microsoft Threat
Intelligence
משאבים
דוגמאות התוכן והקוד שבדף הזה כפופות לרישיונות המפורטים בקטע רישיון לתוכן. Java ו-OpenJDK הם סימנים מסחריים או סימנים מסחריים רשומים של חברת Oracle ו/או של השותפים העצמאיים שלה.
עדכון אחרון: 2025-07-27 (שעון UTC).
[[["התוכן קל להבנה","easyToUnderstand","thumb-up"],["התוכן עזר לי לפתור בעיה","solvedMyProblem","thumb-up"],["סיבה אחרת","otherUp","thumb-up"]],[["חסרים לי מידע או פרטים","missingTheInformationINeed","thumb-down"],["התוכן מורכב מדי או עם יותר מדי שלבים","tooComplicatedTooManySteps","thumb-down"],["התוכן לא עדכני","outOfDate","thumb-down"],["בעיה בתרגום","translationIssue","thumb-down"],["בעיה בדוגמאות/בקוד","samplesCodeIssue","thumb-down"],["סיבה אחרת","otherDown","thumb-down"]],["עדכון אחרון: 2025-07-27 (שעון UTC)."],[],[],null,["# Webviews – Unsafe URI Loading\n\n\u003cbr /\u003e\n\n**OWASP category:** [MASVS-CODE: Code Quality](https://mas.owasp.org/MASVS/10-MASVS-CODE)\n\n\nOverview\n--------\n\nAn unsafe URI Loading occurs when an Android application fails to correctly\nevaluate the validity of a URI before loading it into a WebView.\n\nThe underlying reason behind this type of vulnerability is that a\n[URI consists of multiple parts](https://docs.oracle.com/en/java/javase/20/docs/api/java.base/java/net/URI.html), of which, at a minimum, the scheme and the\nhost (of the authority part) must be verified (e.g. allowlisted) before the URI\ngets loaded to a WebView or is used internally by the application.\n\nThe most common mistakes include:\n\n- Checking the host but not the scheme, allowing an attacker to use schemes like `http://`, `content://` or `javascript://` with an authenticated host.\n- Failing to parse the URI correctly, especially in cases where the URI is received as a string.\n- Validating the scheme but not the host (insufficient host validation).\n\nRegarding the last case, this usually occurs when the application needs to allow\narbitrary subdomains of a primary domain. So, even if the hostname has been\nextracted correctly, the app uses methods such as `startsWith`, `endsWith,` or\n`contains` of the `java.lang.String` class to validate the presence of a primary\ndomain in the extracted string section. Used incorrectly, these methods may lead\nto faulty results and force the application to improperly trust a potentially\nmalicious host.\n\nImpact\n------\n\nDepending on the context in which the host is used, the impact can vary. In\ncases where loading a malicious URI (i.e., one that bypassed\nfiltering/allowlist) in a WebView could potentially lead to account takeover\n(e.g. using phishing), code execution (e.g., loading malicious JavaScript), or\ndevice compromise (exploit code delivered using hyperlink).\n\nMitigations\n-----------\n\nWhen handling string URIs, it is important to parse the string as a URI and\nvalidate both the scheme and the host: \n\n### Kotlin\n\n fun isUriTrusted(incomingUri: String, trustedHostName: String): Boolean {\n try {\n val uri = Uri.parse(incomingUri)\n return uri.scheme == \"https\" && uri.host == trustedHostName\n } catch (e: NullPointerException) {\n throw NullPointerException(\"incomingUri is null or not well-formed\")\n }\n }\n\n### Java\n\n public static boolean isUriTrusted(String incomingUri, String trustedHostName)\n throws NullPointerException {\n try {\n Uri uri = Uri.parse(incomingUri);\n return uri.getScheme().equals(\"https\") &&\n uri.getHost().equals(trustedHostName);\n } catch (NullPointerException e) {\n throw new NullPointerException(\n \"incomingUri is null or not well-formed\");\n }\n }\n\nFor host validation, after isolating the corresponding URI part, it is important\nto validate it entirely (rather than partially) to accurately identify whether\nthe host is trusted or not. When using methods like `startsWith` or `endsWith`\ncan't be avoided, it is important to use the correct syntax and not overlook\nnecessary characters or symbols (for example, `endsWith` requires the \"`.`\" dot\ncharacter before the domain name for an accurate match). Neglecting these\ncharacters may lead to inaccurate matches and compromise security. Since\nsubdomains can be infinitely nested, regular expression matching is not a\nrecommended strategy for validating hostnames.\n\nContributors: Dimitrios Valsamaras and Michael Peck of Microsoft Threat\nIntelligence\n\nResources\n---------\n\n- [getHost() documentation](/reference/java/net/URI#getHost())\n- [getScheme() documentation](/reference/java/net/URI#getScheme())"]]