Adicionar mais cabeçalhos de solicitação HTTP

As solicitações HTTP contêm cabeçalhos como "User-Agent" ou "Content-Type". Além dos cabeçalhos anexados pelos navegadores, os apps Android podem adicionar outros cabeçalhos, como cookie ou referenciador, usando o extra da intent EXTRA_HEADERS. Por motivos de segurança, o Chrome filtra alguns dos cabeçalhos extras, dependendo de como e onde uma intent é iniciada.

As solicitações de origem cruzada exigem uma camada extra de segurança, já que o cliente e o servidor não são de propriedade da mesma parte. Este guia aborda como iniciar essas solicitações usando guias personalizadas do Chrome, ou seja, intents iniciadas em apps que abrem um URL na guia do navegador. Até o Chrome 83, os desenvolvedores podiam adicionar qualquer cabeçalho ao iniciar uma guia personalizada. Da versão 83 em diante, o Chrome começou a filtrar todos os cabeçalhos de origem cruzada, exceto nenhuma aprovação, porque os que não eram aprovados cria um risco à segurança. A partir do Chrome 86, é possível anexar cabeçalhos não aprovados a solicitações de origem cruzada quando o servidor e o cliente estiverem relacionados usando um Digital Asset Link. Esse comportamento está resumido na tabela abaixo:

Versão do Chrome Cabeçalhos CORS permitidos
Antes do Chrome 83 aprovado, não aprovado
Chrome 83 ao Chrome 85 incluído na lista de aprovação
do Chrome 86 em diante "Aprovada", "Não aprovado" quando um Digital Asset Link está configurado

Tabela 1: Filtragem de cabeçalhos CORS não aprovados na lista.

Neste artigo, mostramos como configurar uma conexão verificada entre o servidor e o cliente e usá-la para enviar cabeçalhos HTTP aprovados e não listados. Pule para o artigo Como adicionar cabeçalhos extras a intents de guia personalizadas para ver o código.

Contexto

Cabeçalhos de solicitação de CORS da lista de aprovação x não aprovados

O Compartilhamento de recursos entre origens (CORS, na sigla em inglês) permite que um aplicativo da Web de uma origem solicite recursos de outra origem. A lista de cabeçalhos CORS-APPROVElisting é mantida no padrão HTML. Confira exemplos de cabeçalhos aprovados na próxima tabela:

Cabeçalho Descrição
Aceitar-idioma anuncia linguagens naturais que o cliente entende
content-language descreve a linguagem destinada ao público atual
content-type indica o tipo de mídia do recurso

Tabela 2: Exemplo de cabeçalhos CORS da lista de aprovação.

Os cabeçalhos da lista de aprovação são considerados seguros porque não contêm informações confidenciais do usuário e provavelmente não farão com que o servidor execute operações possivelmente prejudiciais.

Confira na tabela a seguir exemplos de cabeçalhos não aprovados na lista:

Cabeçalho Descrição
token do portador autentica o cliente em um servidor
origin indica a origem da solicitação
biscoito contém cookies definidos pelo servidor

Tabela 3: Exemplo de cabeçalhos CORS não aprovados.

O padrão HTML não recomenda anexar cabeçalhos não aprovados às solicitações CORS, e os servidores presumem que as solicitações de origem cruzada contêm apenas cabeçalhos aprovados. O envio de cabeçalhos não aprovados de domínios de origem cruzada permite que apps de terceiros maliciosos criem cabeçalhos que usam cookies do usuário que o Chrome ou outro navegador armazena e anexa às solicitações. Eles podem autenticar transações maliciosas do servidor que, de outra forma, não seriam possíveis.

Como anexar cabeçalhos da lista de aprovação do CORS às solicitações de guias personalizadas

As guias personalizadas são uma maneira especial de abrir páginas da Web em uma guia personalizada do navegador. As intents de guia personalizada podem ser criadas usando CustomTabsIntent.Builder(). Também é possível anexar cabeçalhos a essas intents usando um Bundle com a sinalização Browser.EXTRA_HEADERS:

CustomTabsIntent intent = new CustomTabsIntent.Builder(session).build();

Bundle headers = new Bundle();
headers.putString("bearer-token", "Some token");
headers.putString("redirect-url", "Some redirect url");   
intent.intent.putExtra(Browser.EXTRA_HEADERS, headers);

intent.launchUrl(Activity.this, Uri.parse("http://www.google.com"));

Podemos sempre anexar cabeçalhos da lista de aprovação a solicitações de CORS de guias personalizadas. No entanto, o Chrome filtra os cabeçalhos não aprovados por padrão. Embora outros navegadores possam ter comportamentos diferentes, os desenvolvedores podem esperar que os cabeçalhos não aprovados sejam bloqueados em geral.

A maneira compatível de incluir cabeçalhos não aprovados na lista de guias personalizadas é primeiro verificar a conexão de origem cruzada usando um link de acesso digital. A próxima seção mostra como configurá-los e iniciar uma intent de guias personalizadas com os cabeçalhos necessários.

Como adicionar cabeçalhos extras a intents de guia personalizada

Para permitir que cabeçalhos não aprovados sejam transmitidos por intents da guia personalizada, é necessário configurar um link de recursos digitais entre o app Android e a Web que verifique se o autor é proprietário dos dois aplicativos.

Siga o guia oficial para configurar um Digital Asset Link. Para a relação de link, use "delegate_permission/common.use_as_origin", que indica que os dois aplicativos pertencem à mesma origem depois que o link é verificado.

Criar um intent de guia personalizada com cabeçalhos extras

Há várias maneiras de criar uma intent de guias personalizadas. Você pode usar o builder disponível no AndroidX adicionando a biblioteca às dependências de build:

MULTI_LINE_CODE_PLACEHOLDER_1

Crie a intent e adicione mais cabeçalhos:

MULTI_LINE_CODE_PLACEHOLDER_2

Uma conexão de guias personalizadas é usada para configurar um CustomTabsSession entre o app e a guia do Chrome. É preciso fazer a sessão para verificar se o app e o app da Web pertencem à mesma origem. A verificação só vai ser aprovada se os Digital Asset Links tiverem sido configurados corretamente.

É recomendável chamar CustomTabsClient.warmup(). Ele permite que o app do navegador seja pré-inicializado em segundo plano e acelere o processo de abertura do URL.

MULTI_LINE_CODE_PLACEHOLDER_3

Configurar um callback que inicie a intent após a validação

A CustomTabsCallback foi transmitida para a sessão. Configuramos o onRelationshipValidationResult() para iniciar a CustomTabsIntent criada anteriormente quando a verificação de origem é bem-sucedida.

MULTI_LINE_CODE_PLACEHOLDER_4

Vincular a conexão do serviço de guias personalizadas

A vinculação do serviço inicia o serviço e o onCustomTabsServiceConnected() da conexão será chamado. Não se esqueça de desvincular o serviço corretamente. Normalmente, a vinculação e a desvinculação são feitas nos métodos onStart() e onStop() do ciclo de vida da atividade.

// Bind the custom tabs service connection.
// Call this in onStart()
CustomTabsClient.bindCustomTabsService(this,
    CustomTabsClient.getPackageName(MainActivity.this, null), connection);

// …
// Unbind the custom tabs service.
// Call this in onStop().
unbindService(connection);

Código do aplicativo de demonstração

Veja mais detalhes sobre o serviço de guias personalizadas aqui. Consulte o repositório do GitHub android-browser-helper para conferir um app de exemplo funcional.

Resumo

Neste guia, mostramos como adicionar cabeçalhos arbitrários às solicitações de CORS de guias personalizadas. Os cabeçalhos listados podem ser anexados a cada solicitação de CORS de guias personalizadas. Geralmente, os cabeçalhos não aprovados são considerados não seguros nas solicitações de CORS e são filtrados pelo Chrome por padrão. Anexá-los só é permitido para clientes e servidores da mesma origem, verificados por um Digital Asset Link.