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 氏