ホワイトリストにURLのhost部分だけじゃなく、pathも含めたい時の対処方法です。
前提条件
URLを開く際、以下のようなことをするAndroidアプリがあると仮定します。
- ↓の処理でホワイトリストとuriのhost部分を比較し、ホワイトリストに登録されている文字列がuriに含まれていたらアプリ内のWebViewで、含まれてなければ外部ブラウザで開く
fun compareWhiteList(uri: Uri): Boolean {
return uri.host in whiteList
}
- ホワイトリストはサーバー上で管理しており、アプリ起動時にFetchしてくる(上記の
whiteList
に格納) - ホワイトリストは以下の文字列が登録されている
hogehoge.com
hugahuga.co.jp
突然の仕様変更
ある日、「ホワイトリストにpiyopoyo.com/system/menu
を追加したい」という要望が上から降ってきました。
現在の実装では、host部分しかホワイトリストと比較していません。さてどうしましょうか…
間違い例
まず初めに、uriにpathを含むホワイトリスト文字列があるかを判定すれば良いのでは?と考え、以下のような処理を追加しました。
fun compareWhiteList(uri: Uri): Boolean {
// path含むホワイトリストの判定
val whiteListWithPathList = whiteList.filter { it.contains("/") } // pathを含むホワイトリストだけ抽出
if (whiteListWithPathList.any { "$uri".contains(it) }) return true // uriに文字列が含まれてればtrueをreturn
// path含むホワイトリストの判定がfalseならば、従来通りhost部分のみを比較
return uri.host in whiteList
}
一見OKなように見えますが、1点問題があります。
これだと、https://google.com?q=piyopoyo.com/system/menu
のようなuriでもWebViewで開いてしまいます。
ホワイトリスト処理として期待される正しい動きではありません。
(※補足)
わざわざwhiteListWithPathList
で抽出してるのは、whiteList
で比較するとhttps://xxx/hogehoge.com
のようなuriも該当してしまうためです。
正解例
「host + path」は前方一致で判定しなくてはなりません。
よって正しくは↓
fun compareWhiteList(uri: Uri): Boolean {
return whiteList.any { "$uri".startsWith("https://$it") } // uriの先頭がhttps://{ホワイトリストの文字列}で始まっているかの判定をreturn
// return uri.host in whiteList ← 上の処理でhostとの比較をまかなえるので削除できる
}
終わり
host + pathのホワイトリストの判定は、前方一致しなければいけないことに気をつけましょう。