WebView – Liaisons natives

Catégorie OWASP : MASVS-PLATFORM : interaction avec la plate-forme

Présentation

Un pont natif, parfois appelé pont JavaScript, est un mécanisme qui facilite la communication entre une WebView et le code Android natif, en utilisant la méthode addJavascriptInterface. Cela permet une communication bidirectionnelle entre le code JavaScript exécuté dans la WebView et le code Java de l'application Android. La méthode addJavascriptInterface expose un objet Java à tous les cadres d'une WebView. N'importe quel cadre peut accéder au nom de l'objet et appeler des méthodes dessus. Cependant, il n'existe aucun mécanisme permettant à l'application vérifier l'origine du frame appelant dans WebView, ce qui renforce la sécurité car la fiabilité du contenu reste indéterminée.

Un pont natif peut également être implémenté avec des canaux de message HTML en utilisant Android WebViewCompat.postWebMessage ou WebMessagePort.postMessage pour communiquer avec le code JavaScript Window.postMessage WebViewCompat.postWebMessage et WebMessagePort.postMessage peuvent accepter les messages JavaScript envoyés via Window.postMessage, qui seront exécutés dans la WebView.

Les ponts natifs présentent plusieurs risques:

  • Ponts basés sur JavascriptInterface :
    • La méthode addJavascriptInterface injecte un objet Java fourni dans chaque frame de la WebView, y compris les iFrames, ce qui signifie qu'il est sensible à une attaque par des tiers malveillants injectant des frames dans un site Web légitime. Les applications ciblant le niveau d'API 16 ou version antérieure sont particulièrement exposées aux attaques, car cette méthode peut être utilisée pour permettre à JavaScript de contrôler l'application hôte.
    • La réflexion de contenu non fiable fourni par l'utilisateur dans des WebView compatibles avec le pont natif permet les attaques de script intersites (XSS).
  • Ponts basés sur MessageChannel :
    • L'absence de vérification de l'origine sur les points de terminaison des canaux de messages signifie que les messages seront acceptés par n'importe quel expéditeur, y compris ceux contenant du code malveillant.
    • Il est possible d'exposer accidentellement Java à du code JavaScript arbitraire.

Impact

Les méthodes addJavascriptInterface, postWebMessage et postMessage peuvent être exploitées par des personnes malveillantes pour accéder, manipuler ou injecter le code qu'elles contrôlent dans une WebView. Cela peut conduire les utilisateurs à être redirigés vers des sites malveillants, charger du contenu malveillant ou exécuter du code malveillant sur leurs appareils peuvent extraire des données sensibles ou procéder à une élévation des privilèges.

Risque : risques liés à addJavascriptInterface

WebView implémente les fonctionnalités de base d'un navigateur, telles que le rendu de la page, la navigation et l'exécution JavaScript. WebView peut être utilisé dans une application pour afficher du contenu web dans la mise en page d'une activité. Implémenter une annonce native dans une WebView à l'aide de la méthode addJavascriptInterface peut créer des problèmes de sécurité tels que les scripts intersites (XSS) ou qui permettent aux pirates informatiques de charger du contenu non approuvé par injection d'interface et manipuler l'hôte application de manière inattendue, en exécutant du code Java avec les autorisations de votre application hôte.

Stratégies d'atténuation

Désactiver JavaScript

Dans les cas où WebView ne nécessite pas JavaScript, n'appelez pas setJavaScriptEnabled dans WebSettings (par exemple, tout en l'affichage de contenu HTML statique). Par défaut, l'exécution JavaScript est désactivée dans WebView.

Supprimer l'interface JavaScript lors du chargement de contenu non approuvé

Assurez-vous que les objets de l'interface JavaScript sont supprimés en appelant removeJavascriptInterface avant que le contenu non approuvé ne soit chargé dans WebView. Par exemple, vous pouvez le faire dans un appel à shouldInterceptRequest.

Kotlin

webView.removeJavascriptInterface("myObject")

Java

webView.removeJavascriptInterface("myObject");

Charger uniquement du contenu Web via HTTPS

Si vous devez charger du contenu non approuvé, assurez-vous que la WebView charge le contenu Web via une connexion chiffrée (voir également nos consignes sur les communications en texte clair). Empêchez le chargement initial de la page sur des connexions non chiffrées en définissant android:usesCleartextTraffic sur false dans le fichier AndroidManifest ou en interdisant le trafic HTTP dans une configuration de sécurité réseau. Pour en savoir plus, consultez la documentation sur usesCleartextTraffic.

XML

<application
    android:usesCleartextTraffic="false">
    <!-- Other application elements -->
</application>

Pour s'assurer que les redirections et la navigation dans l'application n'ont pas lieu sur des applications non chiffrées pour le trafic, recherchez le schéma HTTP dans loadUrl ou shouldInterceptRequest:

Kotlin

fun loadSecureUrl(webView: WebView?, url: String?) {
    webView?.let { wv ->  // Ensure valid WebView and URL
        url?.let {
            try {
                val uri = URI(url)
                if (uri.scheme.equals("https", ignoreCase = true)) { // Enforce HTTPS scheme for security
                    wv.loadUrl(url)
                } else {
                    // Log an error or handle the case where the URL is not secure
                    System.err.println("Attempted to load a non-HTTPS URL: $url")
                }
            } catch (e: Exception) {
                // Handle exception for improper URL format
                System.err.println("Invalid URL syntax: $url")
            }
        }
    }
}

Java

public void loadSecureUrl(WebView webView, String url) {
    if (webView != null && url != null) { // Ensure valid WebView and URL
        try {
            URI uri = new URI(url);
            String scheme = uri.getScheme();
            if ("https".equalsIgnoreCase(scheme)) { // Enforce HTTPS scheme for security
                webView.loadUrl(url);
            } else {
                // Log an error or handle the case where the URL is not secure
                System.err.println("Attempted to load a non-HTTPS URL: " + url);
            }
        } catch (URISyntaxException e) {
            // Handle exception for improper URL format
            System.err.println("Invalid URL syntax: " + url);
        }
    }
}

Valider le contenu non approuvé

Si des liens externes sont chargés dans une WebView, validez le schéma et l'hôte. (domaines de la liste d'autorisation). Les domaines qui ne figurent pas sur la liste d'autorisation doivent être ouverts par le navigateur par défaut.

Ne pas charger de contenu non fiable

Si possible, ne chargez que des URL strictement limitées et du contenu appartenant à l'application. développeur dans WebView.

Ne pas exposer les données sensibles

Si votre application accède à des données sensibles avec une WebView, envisagez d'utiliser la méthode clearCache pour supprimer tous les fichiers stockés localement, avant d'utiliser l'interface JavaScript. Vous pouvez également utiliser des en-têtes côté serveur, tels que "no-store", pour indiquent qu'une application ne doit pas mettre en cache un contenu particulier.

N'exposez pas les fonctionnalités sensibles

Si votre application nécessite des autorisations sensibles ou collecte des données sensibles, vous assurer qu'il est appelé à partir du code de l'application et que ne sont pas divulguées aux utilisateurs. Évitez d'utiliser des interfaces JavaScript pour toute opération ou donnée utilisateur sensible.

Niveau d'API cible 21 ou supérieur

Une méthode sécurisée d'utiliser la méthode addJavascriptInterface consiste à cibler le niveau d'API 21 ou supérieur en vous assurant que la méthode n'est appelée que lorsqu'elle s'exécute au niveau d'API 21 ou supérieur. Avant l'API 21, JavaScript pouvait utiliser la réflexion pour accéder au public d'un objet injecté.


Risque: risques liés à MessageChannel

L'absence de contrôle de l'origine dans postWebMessage() et postMessage() pourrait permettre aux pirates informatiques d'intercepter des messages ou d'en envoyer à des gestionnaires natifs.

Stratégies d'atténuation

Lorsque vous configurez postWebMessage() ou postMessage(), n'autorisez que les messages provenant domaines de confiance en évitant d'utiliser * comme origine cible, et le domaine d'envoi attendu.


Ressources