WebView – 安全でない URI の読み込み
コレクションでコンテンツを整理
必要に応じて、コンテンツの保存と分類を行います。
OWASP カテゴリ: MASVS-CODE: コード品質
概要
安全でない URI の読み込みは、WebView への読み込み前に、Android アプリが URI の有効性を正しく評価できなかった場合に発生します。
この種の脆弱性が生じる根本的な原因は、URI が複数の部分から構成されていることです。URI が WebView に読み込まれる前、またはアプリで内部的に使用される前に、少なくともスキームと(権限部分の)ホストを検証する必要があります(許可リストへの登録など)。
よくある間違いは次のとおりです。
- ホストは確認するがスキームを確認しないため、攻撃者は認証済みのホストで
http://
、content://
、javascript://
などのスキームを使用できてしまう。
- 特に URI が文字列として受信される場合など、URI の解析が正しく行われない。
- スキームは検証するがホストは検証しない(ホストの検証が不十分)。
最後のケースに関しては、通常、プライマリ ドメインの任意のサブドメインをアプリケーションで許可する必要がある場合に発生します。したがって、ホスト名が正しく抽出された場合でも、アプリは java.lang.String
クラスの startsWith
、endsWith,
、contains
などのメソッドを使用して、抽出された文字列セクションにプライマリ ドメインが存在することを検証します。これらのメソッドは、適切な使い方をしなければ正しい結果が得られず、アプリは害を及ぼす恐れのあるホストを妄信してしまう可能性があります。
影響
ホストが使用されるコンテキストによって、影響は異なります。WebView で悪意ある URI(フィルタリングや許可リストを回避した URI)を読み込むと、アカウントの乗っ取り(フィッシングの使用など)やコードの実行(悪意ある 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
ではドメイン名の前に「.
」ドット文字が必要であるなど)を見落とさないことが重要です。これらの文字を無視すると、正確な一致が得られず、セキュリティ侵害につながる可能性があります。サブドメインは無限にネストできるため、正規表現の一致はホスト名を検証するのに推奨される戦略ではありません。
執筆者: Microsoft Threat Intelligence、Dimitrios Valsamaras 氏および Michael Peck 氏
リソース
このページのコンテンツやコードサンプルは、コンテンツ ライセンスに記載のライセンスに従います。Java および OpenJDK は Oracle および関連会社の商標または登録商標です。
最終更新日 2024-02-23 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"]],["最終更新日 2024-02-23 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())"]]