OWASP 類別:MASVS-CODE:程式碼品質
總覽
如果 Android 應用程式無法在將 URI 載入 WebView 前正確評估其有效性,就會發生不安全的 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
需要在網域名稱前加上「.
」點號字元才能正確比對)。省略這些字元可能會導致比對錯誤,並危及安全性。由於子網域可以建立無限的巢狀結構,因此比對規則運算式不是驗證主機名稱時建議採用的策略。