WebView - 不安全的 URI 載入情形

OWASP 類別:MASVS-CODE:程式碼品質

總覽

如果 Android 應用程式無法在將 URI 載入 WebView 前正確評估其有效性,就會發生不安全的 URI 載入情形。

這類安全漏洞背後的根本原因是 URI 內含多個部分;在 URI 載入 WebView 或由應用程式在內部使用時,至少要針對其中的配置和主機 (主機名稱部分) 完成驗證 (例如加入許可清單)。

最常見的錯誤包括:

  • 檢查主機而非配置,以致於讓攻擊者透過經過驗證的主機使用 http://content://javascript:// 等配置。
  • 無法正確剖析 URI,尤其是收到 URI 做為字串時。
  • 驗證配置而非主機 (主機驗證不足)。

以最後一個案例來說,如果應用程式需要允許主網域內的任意子網域,通常就會發生這種情況。因此,即使主機名稱已正確擷取,應用程式還是會使用 java.lang.String 類別的 startsWithendsWith,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 部分後,請務必執行全面驗證 (而非部分驗證),以便準確判定主機是否可受信任。如果不得不使用 startsWithendsWith 等方法,請務必使用正確的語法,不要忽略必要的字元或符號 (例如 endsWith 需要在網域名稱前加上「.」點號字元才能正確比對)。省略這些字元可能會導致比對錯誤,並危及安全性。由於子網域可以建立無限的巢狀結構,因此比對規則運算式不是驗證主機名稱時建議採用的策略。

資源