WebViews: inclusão de arquivos não seguros

Categoria do OWASP: MASVS-STORAGE - Armazenamento (link em inglês)

Visão geral

Este documento aborda vários problemas relacionados à inclusão de arquivos que compartilham mitigações semelhantes. Esses problemas se concentram em vulnerabilidades decorrentes do acesso a arquivos em WebViews e variam de WebSettings perigosos que permitem acesso a arquivos ou ativam o JavaScript a um método WebKit que cria uma solicitação de seleção de arquivos. Este documento é útil se você estiver procurando orientação sobre a correção de problemas no WebView decorrentes do uso do esquema file://, acesso irrestrito a arquivos locais e scripting em vários sites.

Mais especificamente, este documento aborda os seguintes tópicos:

  • WebSettings é uma classe que contém métodos para gerenciar os estados de configuração das WebViews. Esses métodos podem abrir WebViews para diferentes ataques, que serão descritos mais adiante. Neste documento, vamos analisar os métodos relacionados a como os arquivos podem ser acessados e a configuração que permite a execução do JavaScript:
  • Os métodos setAllowFileAccess, setAllowFileAccessFromFileURLs e setAllowUniversalAccessFromFileURLs podem ser usados para conceder acesso a arquivos locais usando um URL de esquema de arquivo (file://). No entanto, eles podem ser explorados por scripts maliciosos para acessar arquivos locais arbitrários a que o aplicativo tem acesso, como a própria pasta /data/. Por isso, esses métodos foram sinalizados como inseguros e descontinuados na API 30 em favor de alternativas mais seguras, como WebViewAssetLoader.
  • O método setJavascriptEnabled pode ser usado para ativar a execução de JavaScript em WebViews. Isso deixa os aplicativos vulneráveis a XSS baseado em arquivos. Principalmente quando configurados para permitir o carregamento de arquivos locais ou conteúdo da Web não confiável que pode conter código executável, configurados para permitir o acesso a arquivos que podem ser criados ou alterados por fontes externas ou permitir que WebViews executem JavaScript, os usuários e os dados deles ficam em risco.
  • WebChromeClient.onShowFileChooser é um método que pertence ao pacote android.webkit, que fornece ferramentas de navegação na Web. Esse método pode ser usado para permitir que os usuários selecionem arquivos em uma WebView. No entanto, esse recurso pode ser usado de forma abusiva porque as WebViews não aplicam restrições sobre qual arquivo é selecionado.

Impacto

O impacto da inclusão de arquivos pode depender de quais WebSettings estão configurados no WebView. Permissões de arquivo muito amplas podem permitir que invasores acessem arquivos locais e roubem dados sensíveis, PII (informações de identificação pessoal) ou dados privados de apps. A ativação da execução de JavaScript pode permitir que invasores executem JavaScript em uma WebView ou no dispositivo de um usuário. Os arquivos selecionados usando o método onShowFileChooser podem comprometer a segurança do usuário, já que não há como o método ou a WebView garantir que a origem do arquivo seja confiável.

Risco: acesso arriscado a arquivos por file://

Ativar setAllowFileAccess, setAllowFileAccessFromFileURLs e setAllowUniversalAccessFromFileURLs pode permitir que intents maliciosos e solicitações WebView com um contexto file:// acessem arquivos locais arbitrários, incluindo cookies WebView e dados particulares do app. Além disso, usar o método onShowFileChooser pode permitir que os usuários selecionem e baixem arquivos de fontes não confiáveis.

Esses métodos podem levar à exfiltração de PII, credenciais de login ou outros dados sensíveis, dependendo da configuração do aplicativo.

Mitigações

Validar URLs de arquivos

Se o app exigir acesso a arquivos por URLs file://, é importante permitir apenas URLs específicos que sejam legítimos, evitando erros comuns.

Usar WebViewAssetLoader

Use WebViewAssetLoader em vez dos métodos mencionados. Esse método usa o esquema http(s)//: em vez de um esquema file:// para acessar recursos do sistema de arquivos local e não é vulnerável ao ataque descrito.

Kotlin

val assetLoader: WebViewAssetLoader = Builder()
  .addPathHandler("/assets/", AssetsPathHandler(this))
  .build()

webView.setWebViewClient(object : WebViewClientCompat() {
  @RequiresApi(21)
  override fun shouldInterceptRequest(view: WebView?, request: WebResourceRequest): WebResourceResponse {
    return assetLoader.shouldInterceptRequest(request.url)
  }

  @Suppress("deprecation") // for API < 21
  override fun shouldInterceptRequest(view: WebView?, url: String?): WebResourceResponse {
    return assetLoader.shouldInterceptRequest(Uri.parse(url))
  }
})

val webViewSettings: WebSettings = webView.getSettings()
// Setting this off for security. Off by default for SDK versions >= 16.
webViewSettings.allowFileAccessFromFileURLs = false
// Off by default, deprecated for SDK versions >= 30.
webViewSettings.allowUniversalAccessFromFileURLs = false
// Keeping these off is less critical but still a good idea, especially if your app is not
// using file:// or content:// URLs.
webViewSettings.allowFileAccess = false
webViewSettings.allowContentAccess = false

// Assets are hosted under http(s)://appassets.androidplatform.net/assets/... .
// If the application's assets are in the "main/assets" folder this will read the file
// from "main/assets/www/index.html" and load it as if it were hosted on:
// https://appassets.androidplatform.net/assets/www/index.html
webView.loadUrl("https://appassets.androidplatform.net/assets/www/index.html")

Java

final WebViewAssetLoader assetLoader = new WebViewAssetLoader.Builder()
         .addPathHandler("/assets/", new AssetsPathHandler(this))
         .build();

webView.setWebViewClient(new WebViewClientCompat() {
    @Override
    @RequiresApi(21)
    public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {
        return assetLoader.shouldInterceptRequest(request.getUrl());
    }

    @Override
    @SuppressWarnings("deprecation") // for API < 21
    public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
        return assetLoader.shouldInterceptRequest(Uri.parse(url));
    }
});

WebSettings webViewSettings = webView.getSettings();
// Setting this off for security. Off by default for SDK versions >= 16.
webViewSettings.setAllowFileAccessFromFileURLs(false);
// Off by default, deprecated for SDK versions >= 30.
webViewSettings.setAllowUniversalAccessFromFileURLs(false);
// Keeping these off is less critical but still a good idea, especially if your app is not
// using file:// or content:// URLs.
webViewSettings.setAllowFileAccess(false);
webViewSettings.setAllowContentAccess(false);

// Assets are hosted under http(s)://appassets.androidplatform.net/assets/... .
// If the application's assets are in the "main/assets" folder this will read the file
// from "main/assets/www/index.html" and load it as if it were hosted on:
// https://appassets.androidplatform.net/assets/www/index.html
webview.loadUrl("https://appassets.androidplatform.net/assets/www/index.html");

Desativar métodos WebSettings perigosos

Os valores dos métodos setAllowFileAccess(), setAllowFileAccessFromFileURLs() e setAllowUniversalAccessFromFileURLs() são definidos como TRUE por padrão no nível 29 da API e em versões anteriores, e como FALSE no nível 30 da API e em versões mais recentes.

Se for necessário configurar outros WebSettings, é melhor desativar esses métodos explicitamente, principalmente para apps destinados a níveis de API menores ou iguais a 29.


Risco: XSS baseado em arquivos

Definir o método setJavacriptEnabled como TRUE permite que o JavaScript seja executado em um WebView. Em combinação com o acesso a arquivos ativado, conforme descrito anteriormente, o XSS baseado em arquivos é possível com a execução de código em arquivos arbitrários ou sites maliciosos abertos no WebView.

Mitigações

Impedir que WebViews carreguem arquivos locais

Assim como no risco anterior, o XSS baseado em arquivos pode ser evitado se setAllowFileAccess(), setAllowFileAccessFromFileURLs() e setAllowUniversalAccessFromFileURLs() forem definidos como FALSE.

Impedir que WebViews executem JavaScript

Defina o método setJavascriptEnabled como FALSE para que o JavaScript não possa ser executado em WebViews.

Impedir que os WebViews carreguem conteúdo não confiável

Às vezes, é necessário ativar essas configurações em WebViews. Nesse caso, é importante garantir que apenas conteúdo confiável seja carregado. Limitar a execução de JavaScript apenas ao que você controla e não permitir JavaScript arbitrário é uma boa maneira de garantir que o conteúdo seja confiável. Caso contrário, impedir que o tráfego de texto não criptografado seja carregado garante que os WebViews com configurações perigosas não possam carregar URLs HTTP. Isso pode ser feito pelo manifesto, definindo android:usesCleartextTraffic como False ou definindo um Network Security Config que proíba o tráfego HTTP.


Recursos