WebView: pontes nativas

Categoria do OWASP: MASVS-PLATFORM - Interação com plataformas

Visão geral

Uma ponte nativa, às vezes conhecida como ponte JavaScript, é um mecanismo que facilita a comunicação entre um WebView e o código nativo do Android, usando o método addJavascriptInterface. Isso permite a comunicação bidirecional entre o código JavaScript em execução no WebView e o código Java do aplicativo Android. O método addJavascriptInterface expõe um objeto Java a todos os frames de um WebView, e qualquer frame pode acessar o nome do objeto e chamar métodos nele. No entanto, não há um mecanismo para o aplicativo verificar a origem do frame de chamada no WebView, o que levanta preocupações de segurança, já que a confiabilidade do conteúdo permanece indeterminada.

Uma ponte nativa também pode ser implementada com canais de mensagens HTML usando o WebViewCompat.postWebMessage ou WebMessagePort.postMessage do Android para se comunicar com o JavaScript Window.postMessage. WebViewCompat.postWebMessage e WebMessagePort.postMessage podem aceitar mensagens JavaScript enviadas por Window.postMessage, que serão executadas no WebView.

Há vários riscos associados a pontes nativas:

  • Pontes baseadas em JavascriptInterface:
    • O método addJavascriptInterface injeta um objeto Java fornecido em todos os frames do WebView, incluindo iframes, o que significa que ele é suscetível a ataques de terceiros maliciosos que injetam frames em um site legítimo. Os aplicativos destinados ao nível 16 da API ou anterior correm um risco maior de ataque, porque esse método pode ser usado para permitir que o JavaScript controle o aplicativo host.
    • Refletir conteúdo não confiável fornecido pelo usuário em WebViews ativados por pontes nativas permite ataques de scripting em vários sites (XSS).
  • Pontes baseadas em MessageChannel:
    • A falta de verificações de origem nos endpoints do canal de mensagens significa que as mensagens serão aceitas de qualquer remetente, incluindo aquelas que contêm código malicioso.
    • É possível expor o Java acidentalmente a JavaScript arbitrário.

Impacto

Os métodos addJavascriptInterface, postWebMessage e postMessage podem ser usados por agentes maliciosos para acessar, manipular ou injetar código controlado em um WebView. Isso pode levar os usuários a serem redirecionados para sites maliciosos, carregar conteúdo malicioso ou executar código malicioso nos dispositivos que podem extrair dados sensíveis ou alcançar o escalonamento de privilégios.

Risco: riscos de addJavascriptInterface

O WebView implementa funcionalidades básicas de um navegador, como renderização de páginas, navegação e execução de JavaScript. O WebView pode ser usado em um aplicativo para mostrar conteúdo da Web como parte de um layout de atividade. A implementação de uma ponte nativa em um WebView usando o método addJavascriptInterface pode criar problemas de segurança, como scripting em vários sites (XSS), ou permitir que invasores carreguem conteúdo não confiável por injeção de interface e manipulem o aplicativo host de maneiras não intencionais, executando código Java com as permissões do aplicativo host.

Mitigações

Desativar JavaScript

Em cenários em que o WebView não exige JavaScript, não chame setJavaScriptEnabled em WebSettings (por exemplo, ao mostrar conteúdo HTML estático). Por padrão, a execução de JavaScript está desativada no WebView.

Remover a interface JavaScript ao carregar conteúdo não confiável

Confirme se os objetos da interface JavaScript foram removidos chamando removeJavascriptInterface antes que o conteúdo não confiável seja carregado pelo WebView. Por exemplo, isso pode ser feito em uma chamada para shouldInterceptRequest.

Kotlin

webView.removeJavascriptInterface("myObject")

Java

webView.removeJavascriptInterface("myObject");

Carregar conteúdo da Web somente por HTTPS

Se você precisar carregar conteúdo não confiável, confirme se o WebView carrega conteúdo da Web em uma conexão criptografada (consulte também nossas diretrizes sobre Comunicações de texto não criptografado). Para evitar que o carregamento de página inicial seja realizado em conexões não criptografadas, defina android:usesCleartextTraffic como false no arquivo AndroidManifest ou impeça o tráfego HTTP em uma configuração de segurança de rede. Consulte a documentação usesCleartextTraffic para mais informações.

XML

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

Para garantir que os redirecionamentos e a navegação adicional do app não ocorram em tráfego não criptografado, verifique o esquema HTTP em 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);
        }
    }
}

Validar conteúdo não confiável

Se algum link externo for carregado em um WebView, valide o esquema e o host (domínios da lista de permissões). Os domínios que não estão na lista de permissões precisam ser abertos pelo navegador padrão.

Não carregar conteúdo não confiável

Se possível, carregue apenas URLs com escopo restrito e conteúdo de propriedade do desenvolvedor do app no WebView.

Não expor dados sensíveis

Se o aplicativo acessar dados sensíveis com um WebView, use o clearCache método para excluir arquivos armazenados localmente antes de usar a interface JavaScript. Você também pode usar cabeçalhos do lado do servidor, como no-store, para indicar que um aplicativo não deve armazenar em cache conteúdos específicos.

Não expor funcionalidades sensíveis

Se o aplicativo exigir permissões sensíveis ou coletar dados sensíveis, confirme se ele é chamado do código no aplicativo e se a divulgação em destaque é fornecida aos usuários. Evite usar interfaces JavaScript para operações sensíveis ou dados do usuário.

Nível desejado da API 21 ou superior

Uma maneira segura de usar o método addJavascriptInterface é segmentar o nível desejado da API 21 ou mais recente, garantindo que o método seja chamado apenas quando executado no nível da API 21 ou mais recente. Antes da API 21, o JavaScript podia usar a reflexão para acessar os campos públicos de um objeto injetado.


Risco: riscos de MessageChannel

A falta de controle de origem em postWebMessage() e postMessage() pode permitir que invasores interceptem mensagens ou enviem mensagens para handlers nativos.

Mitigações

Ao configurar postWebMessage() ou postMessage(), permita apenas mensagens de domínios confiáveis, evitando o uso de * como a origem de destino e, em vez disso, especifique explicitamente o domínio de envio esperado.


Recursos