Ajouter des en-têtes de requête HTTP supplémentaires

Les requêtes HTTP contiennent des en-têtes tels que User-Agent ou Content-Type. En plus des en-têtes ajoutés par les navigateurs, les applications Android peuvent ajouter des en-têtes supplémentaires, comme Cookie ou Referrer, via l'extra d'intent EXTRA_HEADERS. Pour des raisons de sécurité, Chrome filtre certains en-têtes supplémentaires en fonction de la manière et de l'endroit où une intention est lancée.

Les requêtes interorigines nécessitent une couche de sécurité supplémentaire, car le client et le serveur n'appartiennent pas à la même partie. Ce guide explique comment lancer de telles requêtes via les onglets personnalisés de Chrome, c'est-à-dire les intents lancés à partir d'applications qui ouvrent une URL dans l'onglet du navigateur. Jusqu'à Chrome 83, les développeurs pouvaient ajouter des en-têtes lors du lancement d'un onglet personnalisé. À partir de la version 83, Chrome a commencé à filtrer tous les en-têtes interorigines, à l'exception de ceux autorisés, car les en-têtes interorigines non autorisés présentaient un risque pour la sécurité. À partir de Chrome 86, il est possible d'associer des en-têtes non approuvés aux requêtes interorigines lorsque le serveur et le client sont associés à l'aide d'un lien Digital Asset. Ce comportement est résumé dans le tableau suivant :

Version de Chrome En-têtes CORS autorisés
avant Chrome 83 approuvé, non approuvé
Chrome 83 à Chrome 85 ajouté à la liste d'autorisation
à partir de Chrome 86 "approuvé" ou "non approuvé" lorsqu'un lien vers un asset numérique est configuré

Tableau 1 : Filtrage des en-têtes CORS non ajoutés à la liste d'approbation.

Cet article explique comment configurer une connexion validée entre le serveur et le client, et comment l'utiliser pour envoyer des en-têtes HTTP approuvés et non approuvés. Vous pouvez passer directement à la section Ajouter des en-têtes supplémentaires aux intents d'onglets personnalisés pour le code.

Arrière-plan

En-têtes de requêtes CORS approuvés et non approuvés

Le partage des ressources entre origines multiples (CORS, Cross-Origin Resource Sharing) permet à une application Web d'une origine de demander des ressources d'une autre origine. La liste des en-têtes CORS-approvelisted est disponible dans la norme HTML. Vous trouverez des exemples d'en-têtes approuvés dans le tableau ci-dessous :

Header Description
accept-language annonce les langues naturelles que le client comprend.
content-language décrit le langage destiné à l'audience actuelle.
content-type indique le type de support de la ressource.

Tableau 2 : Exemple d'en-têtes CORS approuvés et listés.

Les en-têtes figurant sur la liste d'approbation sont considérés comme sûrs, car ils ne contiennent pas d'informations utilisateur sensibles et sont peu susceptibles d'entraîner des opérations potentiellement dangereuses pour le serveur.

Vous trouverez des exemples d'en-têtes non approuvés dans le tableau suivant :

Header Description
bearer-token authentifie le client auprès d'un serveur.
origin indique l'origine de la demande.
biscuit contient les cookies définis par le serveur.

Tableau 3 : Exemples d'en-têtes CORS ne figurant pas sur la liste d'autorisation.

La norme HTML déconseille d'associer des en-têtes non approuvés aux requêtes CORS. Les serveurs partent du principe que les requêtes interorigines ne contiennent que des en-têtes approuvés. L'envoi d'en-têtes non approuvés à partir de domaines interorigines permettrait à des applications tierces malveillantes de créer des en-têtes qui utilisent de manière abusive les cookies utilisateur que Chrome (ou un autre navigateur) stocke et joint aux requêtes. Les cookies pourraient authentifier des transactions de serveur malveillantes qui ne seraient pas possibles autrement.

Associer des en-têtes CORS approuvés aux requêtes d'onglets personnalisés

Les onglets personnalisés sont un moyen spécial de lancer des pages Web dans un onglet de navigateur personnalisé. Vous pouvez créer des intents d'onglets personnalisés à l'aide de CustomTabsIntent.Builder(). Vous pouvez également joindre des en-têtes à ces intents à l'aide d'un Bundle avec l'option 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"));

Nous pouvons toujours associer des en-têtes approuvés aux requêtes CORS des onglets personnalisés. Toutefois, Chrome filtre les en-têtes non approuvés par défaut. Bien que d'autres navigateurs puissent avoir un comportement différent, les développeurs doivent s'attendre à ce que les en-têtes non approuvés soient bloqués en général.

La méthode recommandée pour inclure des en-têtes non approuvés dans les onglets personnalisés consiste à d'abord valider la connexion interorigine à l'aide d'un lien d'accès numérique. La section suivante explique comment les configurer et lancer un intent d'onglets personnalisés avec les en-têtes requis.

Ajouter des en-têtes supplémentaires aux intents d'onglets personnalisés

Pour autoriser la transmission d'en-têtes non approuvés dans les intents d'onglets personnalisés, il est nécessaire de configurer un lien Digital Asset Links entre l'application Android et l'application Web afin de vérifier que l'auteur est propriétaire des deux applications.

Suivez le guide officiel pour configurer un lien Digital Asset Links. Pour la relation de lien, utilisez "delegate_permission/common.use_as_origin", qui indique que les deux applications appartiennent à la même origine une fois le lien validé.

Créer un intent d'onglet personnalisé avec des en-têtes supplémentaires

Il existe plusieurs façons de créer une intention d'onglets personnalisés. Vous pouvez utiliser le générateur disponible dans AndroidX en ajoutant la bibliothèque aux dépendances de compilation :

implementation 'androidx.browser:browser:1.2.0'

Créez l'intention et ajoutez des en-têtes supplémentaires :

CustomTabsIntent constructExtraHeadersIntent(CustomTabsSession session) {
    CustomTabsIntent intent = new CustomTabsIntent.Builder(session).build();

    // Example non-cors-approvelisted headers.
    Bundle headers = new Bundle();
    headers.putString("bearer-token", "Some token");
    headers.putString("redirect-url", "Some redirect url");
    intent.intent.putExtra(Browser.EXTRA_HEADERS, headers);
    return intent;
}

Une connexion Custom Tabs est utilisée pour configurer un CustomTabsSession entre l'application et l'onglet Chrome. Nous avons besoin de la session pour vérifier que l'application et l'application Web appartiennent à la même origine. La validation n'est acceptée que si les liens Digital Asset Links ont été correctement configurés.

Nous vous encourageons à appeler le CustomTabsClient.warmup(). Elle permet à l'application de navigateur de se pré-initialiser en arrière-plan et d'accélérer le processus d'ouverture des URL.

// Set up a connection that warms up and validates a session.
CustomTabsServiceConnection connection = new CustomTabsServiceConnection() {
    @Override
    public void onCustomTabsServiceConnected(@NonNull ComponentName name, 
        @NonNull CustomTabsClient client) {
        // Create session after service connected.
        mSession = client.newSession(callback);
        client.warmup(0);
        // Validate the session as the same origin to allow cross origin headers.
        mSession.validateRelationship(CustomTabsService.RELATION_USE_AS_ORIGIN, 
            Uri.parse(url), null);
    }
    @Override
    public void onServiceDisconnected(ComponentName componentName) { }
};

Configurer un rappel qui lance l'intention après la validation

Le CustomTabsCallback a été transmis à la session. Nous configurons son onRelationshipValidationResult() pour lancer le CustomTabsIntent précédemment créé une fois la validation de l'origine réussie.

// Set up a callback that launches the intent after session validated.
CustomTabsCallback callback = new CustomTabsCallback() {
    @Override
    public void onRelationshipValidationResult(int relation, @NonNull Uri requestedOrigin, 
        boolean result, @Nullable Bundle extras) {
        // Launch custom tabs intent after session was validated as the same origin.
        CustomTabsIntent intent = constructExtraHeadersIntent(mSession);
        intent.launchUrl(MainActivity.this, Uri.parse(url));
    }
};

Associer la connexion au service d'onglets personnalisés

La liaison du service lance le service et le onCustomTabsServiceConnected() de la connexion sera appelé par la suite. N'oubliez pas de dissocier le service de manière appropriée. L'association et la dissociation sont généralement effectuées dans les méthodes de cycle de vie des activités onStart() et 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);

Code de l'application de démonstration

Pour en savoir plus sur le service d'onglets personnalisés, cliquez ici. Pour obtenir un exemple d'application fonctionnel, consultez le dépôt GitHub android-browser-helper.

Résumé

Ce guide explique comment ajouter des en-têtes arbitraires aux requêtes CORS des onglets personnalisés. Les en-têtes approuvés peuvent être associés à chaque requête CORS des onglets personnalisés. Les en-têtes ne figurant pas sur la liste d'approbation sont généralement considérés comme dangereux dans les requêtes CORS et Chrome les filtre par défaut. Il n'est autorisé de les joindre que pour les clients et les serveurs de même origine, validés par un lien Digital Asset Links.