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 por navegadores, os apps Android podem adicionar cabeçalhos extras, como Cookie ou Referrer, usando a intent extra 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 entre origens 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 discute o lançamento dessas solicitações usando guias personalizadas do Chrome, ou seja, intents iniciadas por 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. A partir da versão 83, o Chrome começou a filtrar todos os cabeçalhos de origem cruzada, exceto os aprovados, porque os cabeçalhos não aprovados representavam um risco de segurança. A partir do Chrome 86, é possível anexar cabeçalhos não aprovados à lista a solicitações entre origens diferentes quando o servidor e o cliente estão relacionados usando um link de recurso digital. Esse comportamento é resumido na tabela a seguir:

Versão do Chrome Cabeçalhos CORS permitidos
antes do Chrome 83 em lista de aprovados e não aprovados
Do Chrome 83 ao Chrome 85 na lista de permissões
do Chrome 86 em diante na lista de aprovação, fora da lista de aprovação quando um link de recurso digital é configurado

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

Este artigo mostra como configurar uma conexão verificada entre o servidor e o cliente e usá-la para enviar cabeçalhos HTTP aprovados e não aprovados. Você pode pular para Adicionar cabeçalhos extras às intents de guias personalizadas para conferir o código.

Contexto

Cabeçalhos de solicitação de CORS com e sem lista de aprovação

O Compartilhamento de recursos entre origens (CORS) permite que um aplicativo da Web de uma origem solicite recursos de outra origem. A lista de cabeçalhos aprovados pelo CORS é mantida no padrão HTML. Confira na tabela a seguir exemplos de cabeçalhos na lista de aprovação:

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

Tabela 2: Exemplo de cabeçalhos CORS aprovados.

Os cabeçalhos da lista de aprovação são considerados seguros porque não contêm informações sensíveis do usuário e dificilmente fazem com que o servidor realize operações potencialmente prejudiciais.

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

Cabeçalho Descrição
bearer-token autentica o cliente em um servidor
origem indica a origem da solicitação
biscoito Contém cookies definidos pelo servidor

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

O anexo de cabeçalhos não aprovados às solicitações do CORS é desencorajado pelo padrão HTML, e os servidores assumem 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 permitiria que apps de terceiros maliciosos criassem cabeçalhos que usam indevidamente cookies do usuário que o Chrome (ou outro navegador) armazena e anexa às solicitações. Os cookies podem autenticar transações maliciosas do servidor que, de outra forma, não seriam possíveis.

Como anexar cabeçalhos aprovados do CORS a solicitações de guias personalizadas

As Guias personalizadas são uma maneira especial de abrir páginas da Web em uma guia de navegador personalizada. As intents de guias personalizadas podem ser criadas usando CustomTabsIntent.Builder(). Também é possível anexar cabeçalhos a essas intents usando um Bundle com a flag 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 anexar cabeçalhos aprovados às solicitações CORS de guias personalizadas. No entanto, o Chrome filtra cabeçalhos não aprovados por padrão. Embora outros navegadores possam ter um comportamento diferente, os desenvolvedores devem esperar que os cabeçalhos não aprovados sejam bloqueados em geral.

A maneira recomendada de incluir cabeçalhos não aprovados na lista em guias personalizadas é verificar primeiro a conexão entre origens diferentes usando um link de acesso digital. A próxima seção mostra como configurar essas intent e iniciar uma intent das guias personalizadas com os cabeçalhos necessários.

Como adicionar cabeçalhos extras às intents de guias personalizadas

Para permitir que cabeçalhos não aprovados sejam transmitidos por intents de guias personalizadas, é necessário configurar um link de recurso digital entre o aplicativo Android e o da Web que verifique se o autor é proprietário de ambos.

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

Criar uma intent de guia personalizada com cabeçalhos extras

Há várias maneiras de criar uma intent de guias personalizadas. É possível 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 cabeçalhos extras:

MULTI_LINE_CODE_PLACEHOLDER_2

Uma conexão de guias personalizadas é usada para configurar um CustomTabsSession entre o app e a guia do Chrome. Precisamos da sessão para verificar se o app e o app da Web pertencem à mesma origem. A verificação só é aprovada se os links de recursos digitais forem configurados corretamente.

É recomendável chamar CustomTabsClient.warmup(). Ele permite que o aplicativo 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 inicia a intent após a validação

O CustomTabsCallback foi transmitido para a sessão. Configuramos o onRelationshipValidationResult() para iniciar o CustomTabsIntent criado anteriormente assim que a verificação de origem for bem-sucedida.

MULTI_LINE_CODE_PLACEHOLDER_4

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

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

// 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

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

Resumo

Este guia demonstrou como adicionar cabeçalhos arbitrários às solicitações CORS de guias personalizadas. Cabeçalhos em lista de aprovação podem ser anexados a todas as solicitações CORS de guias personalizadas. Os cabeçalhos não aprovados geralmente são considerados inseguros em solicitações CORS, e o Chrome os filtra por padrão. A vinculação deles é permitido apenas para clientes e servidores da mesma origem, verificados por um link de recurso digital.