مشاهدات الويب - تحميل عنوان URL غير آمن
تنظيم صفحاتك في مجموعات
يمكنك حفظ المحتوى وتصنيفه حسب إعداداتك المفضّلة.
فئة OWASP: MASVS-CODE: جودة الرمز
نظرة عامة
يحدث تحميل معرّف موارد منتظم غير آمن عندما يتعذّر على تطبيق Android تقييم صلاحية معرّف الموارد المنتظم بشكل صحيح قبل تحميله في WebView.
السبب الأساسي وراء هذا النوع من الثغرات الأمنية هو أنّ معرّف الموارد الموحّد يتألف من أجزاء متعددة، ويجب التحقّق من المخطط والمضيف (جزء السلطة) على الأقل (مثل إضافتهما إلى القائمة المسموح بها) قبل تحميل معرّف الموارد الموحّد إلى WebView أو استخدامه داخليًا بواسطة التطبيق.
تشمل الأخطاء الأكثر شيوعًا ما يلي:
- التحقّق من المضيف بدون التحقّق من المخطط، ما يسمح للمهاجم باستخدام مخططات مثل
http://
أو content://
أو javascript://
مع مضيف مصادق عليه
- تعذُّر تحليل معرّف الموارد المنتظم (URI) بشكل صحيح، خاصةً في الحالات التي يتم فيها تلقّي معرّف الموارد المنتظم (URI) كسلسلة
- التحقّق من صحة المخطط ولكن ليس المضيف (التحقّق غير الكافي من صحة المضيف)
في ما يتعلّق بالحالة الأخيرة، يحدث ذلك عادةً عندما يحتاج التطبيق إلى السماح بنطاقات فرعية عشوائية لنطاق أساسي. لذلك، حتى إذا تم استخراج اسم المضيف بشكل صحيح، يستخدم التطبيق طرقًا مثل startsWith
أو endsWith,
أو contains
من فئة java.lang.String
للتحقّق من توفّر نطاق أساسي في قسم السلسلة المستخرَجة. وقد يؤدي الاستخدام غير الصحيح لهذه الطرق إلى نتائج خاطئة وإجبار التطبيق على الوثوق بشكل غير صحيح بمضيف يحتمل أن يكون ضارًا.
التأثير
قد يختلف التأثير حسب السياق الذي يتم فيه استخدام المضيف. في الحالات التي قد يؤدي فيها تحميل معرّف URI ضار (أي معرّف تجاوز الفلترة أو قائمة السماح) في WebView إلى الاستيلاء على الحساب (مثل استخدام التصيّد الاحتيالي) أو تنفيذ التعليمات البرمجية (مثل تحميل JavaScript الضار) أو اختراق الجهاز (تعليمات برمجية للاستغلال يتم تسليمها باستخدام ارتباط تشعّبي).
إجراءات التخفيف
عند التعامل مع معرّفات الموارد المنتظمة (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
النقطة ".
"
قبل اسم النطاق للحصول على تطابق دقيق). قد يؤدي إهمال هذه الأحرف إلى عدم تطابق النتائج بدقة وتعريض الأمان للخطر. بما أنّ النطاقات الفرعية يمكن أن تكون متداخلة إلى ما لا نهاية، لا يُنصح باستخدام مطابقة التعبيرات العادية كاستراتيجية للتحقّق من صحة أسماء المضيفين.
المساهمون: ديميتريوس فالساماراس ومايكل بيك من فريق Microsoft Threat Intelligence
المراجع
يخضع كل من المحتوى وعيّنات التعليمات البرمجية في هذه الصفحة للتراخيص الموضحّة في ترخيص استخدام المحتوى. إنّ Java وOpenJDK هما علامتان تجاريتان مسجَّلتان لشركة Oracle و/أو الشركات التابعة لها.
تاريخ التعديل الأخير: 2025-07-27 (حسب التوقيت العالمي المتفَّق عليه)
[[["يسهُل فهم المحتوى.","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 (حسب التوقيت العالمي المتفَّق عليه)"],[],[],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())"]]