Webview – Pemuatan URI Tidak Aman
Tetap teratur dengan koleksi
Simpan dan kategorikan konten berdasarkan preferensi Anda.
Kategori OWASP: MASVS-CODE: Kualitas Kode
Ringkasan
Pemuatan URI yang Tidak Aman terjadi saat aplikasi Android gagal
mengevaluasi validitas URI dengan benar sebelum memuatnya ke WebView.
Alasan yang mendasari jenis kerentanan ini adalah bahwa
URI terdiri dari beberapa bagian, yang setidaknya,
skema dan host (dari bagian otoritas) harus terverifikasi (misalnya diizinkan)
sebelum URI dimuat ke WebView atau digunakan secara internal oleh
aplikasi.
Kesalahan yang paling umum meliputi:
- Memeriksa host, tetapi tidak memeriksa skema sehingga penyerang dapat menggunakan skema seperti
http://
, content://
, atau javascript://
dengan host yang diautentikasi.
- Gagal mengurai URI dengan benar, terutama ketika URI
diterima sebagai string.
- Memvalidasi skema, tetapi tidak memvalidasi host (validasi host tidak memadai).
Terkait dengan kasus terakhir, hal ini biasanya terjadi saat aplikasi perlu mengizinkan
subdomain arbitrer dari domain primer. Jadi, meskipun nama host telah
diekstrak dengan benar, aplikasi akan menggunakan metode seperti startsWith
, endsWith,
, atau
contains
dari class java.lang.String
untuk memvalidasi keberadaan domain
primer di bagian string yang diekstrak. Jika tidak digunakan dengan benar, metode ini dapat
menyebabkan hasil yang salah dan memaksa aplikasi untuk memercayai host
yang berpotensi berbahaya.
Dampak
Dampak dapat bervariasi bergantung pada konteks tempat host digunakan. Memuat
URI berbahaya (yaitu yang mengabaikan
pemfilteran/daftar yang diizinkan) di WebView berpotensi menyebabkan pengambilalihan akun
(mis. menggunakan phishing), eksekusi kode (mis., memuat JavaScript berbahaya), atau
pembobolan perangkat (mengeksploitasi kode yang dikirimkan menggunakan hyperlink).
Mitigasi
Saat menangani URI string, sebaiknya urai string sebagai URI serta
lakukan validasi skema dan host:
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");
}
}
Untuk validasi host, setelah mengisolasi bagian URI yang sesuai, sebaiknya
lakukan validasi host sepenuhnya (bukan sebagian) guna mengidentifikasi secara akurat apakah
host dipercaya atau tidak. Jika penggunaan metode seperti startsWith
atau endsWith
tidak dapat dihindari, sebaiknya gunakan sintaksis yang benar dan tidak mengabaikan
karakter atau simbol yang diperlukan (misalnya, endsWith
memerlukan karakter titik
".
" sebelum nama domain untuk pencocokan yang akurat). Tidak mencantumkan
karakter ini dapat menyebabkan pencocokan yang tidak akurat dan membahayakan keamanan. Karena
subdomain dapat disusun bertingkat tanpa batasan, pencocokan ekspresi reguler bukanlah
strategi yang direkomendasikan untuk memvalidasi nama host.
Referensi
Konten dan contoh kode di halaman ini tunduk kepada lisensi yang dijelaskan dalam Lisensi Konten. Java dan OpenJDK adalah merek dagang atau merek dagang terdaftar dari Oracle dan/atau afiliasinya.
Terakhir diperbarui pada 2023-12-14 UTC.
[[["Mudah dipahami","easyToUnderstand","thumb-up"],["Memecahkan masalah saya","solvedMyProblem","thumb-up"],["Lainnya","otherUp","thumb-up"]],[["Informasi yang saya butuhkan tidak ada","missingTheInformationINeed","thumb-down"],["Terlalu rumit/langkahnya terlalu banyak","tooComplicatedTooManySteps","thumb-down"],["Sudah usang","outOfDate","thumb-down"],["Masalah terjemahan","translationIssue","thumb-down"],["Masalah kode / contoh","samplesCodeIssue","thumb-down"],["Lainnya","otherDown","thumb-down"]],["Terakhir diperbarui pada 2023-12-14 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())"]]