MASTG-KNOW-0018: WebViews
Carregamento de URL em WebViews¶
Os WebViews são componentes embutidos do Android que permitem que seu aplicativo abra páginas da web dentro da sua aplicação. Além das ameaças relacionadas a aplicativos móveis, os WebViews podem expor seu aplicativo a ameaças comuns da web (por exemplo, XSS, redirecionamento aberto, etc.).
Uma das coisas mais importantes a fazer ao testar WebViews é garantir que apenas conteúdo confiável possa ser carregado nele. Qualquer página recém-carregada pode ser potencialmente maliciosa, tentar explorar quaisquer vinculações do WebView ou tentar realizar phishing contra o usuário. A menos que você esteja desenvolvendo um aplicativo de navegador, geralmente você gostaria de restringir as páginas carregadas ao domínio do seu aplicativo. Uma boa prática é impedir que o usuário sequer tenha a chance de inserir URLs dentro dos WebViews (que é o padrão no Android) nem navegar fora dos domínios confiáveis. Mesmo ao navegar em domínios confiáveis, ainda há o risco de o usuário encontrar e clicar em outros links para conteúdo não confiável (por exemplo, se a página permitir que outros usuários postem comentários). Além disso, alguns desenvolvedores podem até substituir algum comportamento padrão que pode ser potencialmente perigoso para o usuário.
API SafeBrowsing¶
Para fornecer uma experiência de navegação mais segura, o Android 8.1 (nível de API 27) introduz a API SafeBrowsing, que permite que seu aplicativo detecte URLs que o Google classificou como uma ameaça conhecida.
Por padrão, os WebViews mostram um aviso aos usuários sobre o risco de segurança com a opção de carregar a URL ou parar o carregamento da página. Com a API SafeBrowsing, você pode personalizar o comportamento do seu aplicativo relatando a ameaça ao SafeBrowsing ou executando uma ação específica, como retornar à segurança sempre que encontrar uma ameaça conhecida. Consulte a documentação do Android Developers para exemplos de uso.
Você pode usar a API SafeBrowsing independentemente dos WebViews usando a biblioteca SafetyNet, que implementa um cliente para o Protocolo de Rede Safe Browsing v4. A SafetyNet permite analisar todas as URLs que seu aplicativo deve carregar. Você pode verificar URLs com diferentes esquemas (por exemplo, http, file), já que o SafeBrowsing é agnóstico em relação a esquemas de URL, e contra os tipos de ameaça TYPE_POTENTIALLY_HARMFUL_APPLICATION e TYPE_SOCIAL_ENGINEERING.
Ao enviar URLs ou arquivos para verificação de ameaças conhecidas, certifique-se de que eles não contenham dados sensíveis que possam comprometer a privacidade de um usuário ou expor conteúdo sensível do seu aplicativo.
API Virus Total¶
O Virus Total fornece uma API para analisar URLs e arquivos locais em busca de ameaças conhecidas. A Referência da API está disponível na página de desenvolvedores do Virus Total.
Execução de JavaScript em WebViews¶
O JavaScript pode ser injetado em aplicações web por meio de Cross-Site Scripting (XSS) refletido, armazenado ou baseado em DOM. Aplicativos móveis são executados em um ambiente sandboxed e não têm essa vulnerabilidade quando implementados nativamente. No entanto, os WebViews podem fazer parte de um aplicativo nativo para permitir a visualização de páginas da web. Cada aplicativo tem seu próprio cache do WebView, que não é compartilhado com o navegador nativo ou outros aplicativos.
Em versões do Android anteriores à 4.4, os WebViews usavam o mecanismo de renderização WebKit para exibir páginas da web. Desde o Android 4.4, os WebViews são baseados no Chromium, fornecendo melhor desempenho e compatibilidade. No entanto, as páginas ainda são reduzidas a funções mínimas; por exemplo, as páginas não têm barras de endereço.
Os WebViews do Android podem usar setJavaScriptEnabled para habilitar a execução de JavaScript. Esse recurso está desabilitado por padrão, mas se habilitado, pode ser usado para executar código JavaScript no contexto da página carregada. Isso pode ser perigoso se o WebView estiver carregando conteúdo não confiável, pois pode levar a ataques XSS. Se você precisar habilitar JavaScript, certifique-se de que o conteúdo é confiável e que você implementou validação de entrada e codificação de saída adequadas. Caso contrário, você pode explicitamente desabilitar o JavaScript:
webView.settings.apply {
javaScriptEnabled = false
}
Configurações de Acesso a Arquivos Locais no WebView¶
Essas APIs controlam como um WebView acessa arquivos no dispositivo local. Elas determinam se o WebView pode carregar arquivos (como HTML, imagens ou scripts) do sistema de arquivos e se o JavaScript executado em um contexto local pode acessar arquivos locais adicionais. Observe que o acesso a assets e recursos (via file:///android_asset ou file:///android_res) é sempre permitido, independentemente dessas configurações.
| API | Propósito | Padrão True (Nível de API) |
Padrão False (Nível de API) |
Preterida |
|---|---|---|---|---|
setAllowFileAccess |
Permite que o WebView carregue arquivos do sistema de arquivos local (usando URLs file://) |
<= 29 (Android 10) | >= 30 (Android 11) | Não |
setAllowFileAccessFromFileURLs |
Permite que JavaScript em um contexto file:// acesse outras URLs locais file:// |
<= 15 (Android 4.0.3) | >= 16 (Android 4.1) | Sim (desde o nível de API 30, Android 11) |
setAllowUniversalAccessFromFileURLs |
Permite que JavaScript em um contexto file:// acesse recursos de qualquer origem, contornando a política de mesma origem |
<= 15 (Android 4.0.3) | >= 16 (Android 4.1) | Sim (desde o nível de API 30, Android 11) |
Quais arquivos podem ser acessados pelo WebView?:
O WebView pode acessar qualquer arquivo que o aplicativo tem permissão para acessar via URLs file://, incluindo:
- Armazenamento interno: o próprio armazenamento interno do aplicativo.
- Armazenamento externo
- Antes do Android 10:
- todo o armazenamento externo (cartão SD), se o aplicativo tiver a permissão
READ_EXTERNAL_STORAGE.
- todo o armazenamento externo (cartão SD), se o aplicativo tiver a permissão
- Desde o Android 10:
- apenas os diretórios específicos do aplicativo (devido a restrições de armazenamento com escopo) sem quaisquer permissões especiais.
- pastas de mídia inteiras (incluindo dados de outros aplicativos) se o aplicativo tiver as permissões
READ_MEDIA_IMAGESou similares. - todo o armazenamento externo se o aplicativo tiver a permissão
MANAGE_EXTERNAL_STORAGE.
- Antes do Android 10:
setAllowFileAccess¶
setAllowFileAccess permite que o WebView carregue arquivos locais usando o esquema file://. Neste exemplo, o WebView é configurado para permitir acesso a arquivos e, em seguida, carrega um arquivo HTML do armazenamento externo (sdcard).
webView.settings.apply {
allowFileAccess = true
}
webView.loadUrl("file:///sdcard/index.html");
setAllowFileAccessFromFileURLs¶
setAllowFileAccessFromFileURLs permite que o arquivo local (carregado via file://) acesse recursos locais adicionais a partir de seu HTML ou JavaScript.
Observe que o valor dessa configuração é ignorado se o valor de allowUniversalAccessFromFileURLs for true.
Documentação do Chromium WebView: Com essa regra de origem relaxada, URLs iniciadas com
content://efile://podem acessar recursos que têm a mesma origem relaxada viaXMLHttpRequest. Por exemplo,file://foopode fazer umXMLHttpRequestparafile://bar. Os desenvolvedores precisam ter cuidado para que os dados fornecidos pelo usuário não sejam executados emcontent://, pois isso permitirá que o código do usuário acesse URLscontent://arbitrários fornecidos por outros aplicativos. Isso causará um problema de segurança sério.Independente dessa chamada de API, a Fetch API não permite acessar URLs
content://efile://.
Exemplo: Neste exemplo, o WebView é configurado para permitir acesso a arquivos e, em seguida, carrega um arquivo HTML do armazenamento externo (sdcard).
webView.settings.apply {
allowFileAccess = true
allowFileAccessFromFileURLs = true
}
webView.loadUrl("file:///sdcard/local_page.html");
O arquivo HTML carregado contém uma imagem que é carregada via uma URL file://:
<!-- Em local_page.html -->
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Página Local</title>
</head>
<body>
<!-- Esta imagem é carregada via uma URL file:// -->
<img src="file:///android_asset/images/logo.png" alt="Logo">
</body>
</html>
setAllowUniversalAccessFromFileURLs¶
setAllowUniversalAccessFromFileURLs permite que o JavaScript executado em um arquivo local (carregado via file://) ignore a política de mesma origem e acesse recursos de qualquer origem.
Documentação do Chromium WebView: Quando esta API é chamada com true, URLs iniciadas com
file://terão uma origem baseada em esquema e poderão acessar outras URLs baseadas em esquema viaXMLHttpRequest. Por exemplo,file://foopode fazer umXMLHttpRequestparacontent://bar,http://example.com/ehttps://www.google.com/. Portanto, os desenvolvedores precisam gerenciar dados executados sob o esquemafile://, pois isso permite permissões poderosas além da política CORS da web pública.Independente dessa chamada de API, a Fetch API não permite acessar URLs
content://efile://.
Exemplo: Neste exemplo, o arquivo HTML local faz com sucesso uma solicitação de origem cruzada para buscar dados de um endpoint HTTPS. Isso pode ser potencialmente abusado por um atacante para exfiltrar dados sensíveis do aplicativo.
webView.settings.apply {
javaScriptEnabled = true
allowFileAccess = true
allowUniversalAccessFromFileURLs = true
}
webView.loadUrl("file:///android_asset/local_page.html");
Conteúdo de local_page.html (na pasta assets):
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Demonstração de Acesso Universal</title>
<script>
// Esta chamada AJAX busca dados de um servidor remoto apesar de ser carregada via file://
fetch("https://api.example.com/data")
.then(response => response.text())
.then(data => document.getElementById("output").innerText = data)
.catch(err => console.error(err));
</script>
</head>
<body>
<div id="output">Carregando...</div>
</body>
</html>
Nota sobre acesso a cookies:
Definir setAllowUniversalAccessFromFileURLs(true) permite que o JavaScript dentro de um file:// local faça solicitações de origem cruzada (XHR, Fetch, etc.). Isso ignora a Política de Mesma Origem (SOP) para solicitações de rede, mas não concede acesso a cookies de sites remotos.
- Os cookies são gerenciados pelo CookieManager do WebView e não podem ser acessados por uma origem
file://, a menos que explicitamente permitido via document.cookie (o que a maioria dos sites modernos impede usando flagsHttpOnlyeSecure). - Solicitações de origem cruzada também não incluem cookies, a menos que explicitamente permitido pelo servidor via cabeçalhos CORS, como
Access-Control-Allow-Origin: *eAccess-Control-Allow-Credentials: true.
Acesso a Content Providers pelo WebView¶
Os WebViews podem acessar content providers, que são usados para compartilhar dados entre aplicativos. Os content providers podem ser acessados por outros aplicativos apenas se forem exportados (atributo android:exported definido como true), mas mesmo que o content provider não seja exportado, ele pode ser acessado por um WebView no próprio aplicativo.
A configuração setAllowContentAccess controla se o WebView pode acessar content providers usando URLs content://. Essa configuração está habilitada por padrão para Android 4.1 (nível de API 16) e superior.
Documentação do Chromium WebView: URLs
content://são usadas para acessar recursos fornecidos por meio de Content Providers do Android. O acesso deve ser permitido previamente via APIsetAllowContentAccess. Páginascontent://podem conter iframes que carregam páginascontent://, mas o frame pai não pode acessar o conteúdo do iframe. Além disso, apenas páginascontent://podem especificar URLscontent://para sub-recursos.No entanto, mesmo páginas carregadas de
content://não podem fazer solicitações habilitadas para CORS, comoXMLHttpRequest, para outras URLscontent://, pois cada uma é assumida como pertencente a uma origem opaca. Consulte também as seçõessetAllowFileAccessFromFileURLsesetAllowUniversalAccessFromFileURLs, pois elas podem relaxar essa regra padrão.Páginas carregadas com qualquer esquema diferente de
content://não podem carregar páginascontent://em iframes e não podem especificar URLscontent://para sub-recursos.
Exemplo: Neste exemplo, a propriedade allowContentAccess do WebView é habilitada e uma URL content:// é carregada.
webView.settings.apply {
allowContentAccess = true
}
webView.loadUrl("content://com.example.myapp.provider/data");
Quais arquivos podem ser acessados pelo WebView?:
O WebView pode acessar quaisquer dados acessíveis via content providers (se o aplicativo tiver algum) usando URLs content://. A menos que restringido de outra forma pelo content provider, isso pode incluir:
- Armazenamento interno: todo o armazenamento interno.
- Armazenamento externo
- Antes do Android 10:
- todo o armazenamento externo (cartão SD), se o aplicativo tiver a permissão
READ_EXTERNAL_STORAGE.
- todo o armazenamento externo (cartão SD), se o aplicativo tiver a permissão
- Desde o Android 10:
- apenas os diretórios específicos do aplicativo (devido a restrições de armazenamento com escopo) sem quaisquer permissões especiais.
- pastas de mídia inteiras (incluindo dados de outros aplicativos) se o aplicativo tiver as permissões
READ_MEDIA_IMAGESou similares. - todo o armazenamento externo se o aplicativo tiver a permissão
MANAGE_EXTERNAL_STORAGE.
- Antes do Android 10:
Dados de outros aplicativos acessíveis via content providers (se o aplicativo tiver algum e eles forem exportados) também podem ser acessados.
Objetos Java Expostos Através de WebViews¶
O Android oferece uma maneira para a execução de JavaScript em um WebView chamar e usar funções nativas de um aplicativo Android (anotadas com @JavascriptInterface) usando o método addJavascriptInterface. Isso é conhecido como uma ponte JavaScript do WebView ou ponte nativa.
Observe que quando você usa addJavascriptInterface, você está explicitamente concedendo acesso ao objeto JavaScript Interface registrado a todas as páginas carregadas dentro desse WebView. Isso implica que, se o usuário navegar para fora do seu aplicativo ou domínio, todas as outras páginas externas também terão acesso a esses objetos JavaScript Interface, o que pode apresentar um risco de segurança potencial se qualquer dado sensível estiver sendo exposto por meio dessas interfaces.
Aviso: Tome extremo cuidado com aplicativos direcionados a versões do Android abaixo do Android 4.2 (nível de API 17), pois eles são vulneráveis a uma falha na implementação de
addJavascriptInterface: um ataque que abusa de reflexão, levando à execução remota de código quando JavaScript malicioso é injetado em um WebView. Isso ocorreu porque todos os métodos de Object Java eram acessíveis por padrão (em vez de apenas os anotados).
Limpeza de WebViews¶
Limpar os recursos do WebView é uma etapa crucial quando um aplicativo acessa quaisquer dados sensíveis dentro de um WebView. Isso inclui quaisquer arquivos armazenados localmente, o cache da RAM e qualquer JavaScript carregado.
Como uma medida adicional, você pode usar cabeçalhos do lado do servidor, como no-cache, que impedem que um aplicativo armazene em cache determinado conteúdo.
A partir do Android 10 (nível de API 29), os aplicativos podem detectar se um WebView ficou sem resposta. Se isso acontecer, o SO chamará automaticamente o método
onRenderProcessUnresponsive.
Você pode encontrar mais práticas recomendadas de segurança ao usar WebViews no Android Developers.