Zusätzliche HTTP-Anfrageheader hinzufügen

HTTP-Anfragen enthalten Header wie „User-Agent“ oder „Content-Type“. Abgesehen von Headern, die von Browsern angehängt werden, können Android-Apps über das Intent-Extra EXTRA_HEADERS zusätzliche Header wie „Cookie“ oder „Referrer“ hinzufügen. Aus Sicherheitsgründen filtert Chrome einige der zusätzlichen Headern, je nachdem, wie und wo eine Absicht gestartet wird.

Domainübergreifende Anfragen erfordern eine zusätzliche Sicherheitsebene, da Client und Server nicht derselben Partei gehören. In diesem Leitfaden wird beschrieben, wie solche Anfragen über benutzerdefinierte Chrome-Tabs gestartet werden, d.h. Intents, die von Apps gestartet werden und eine URL im Browser-Tab öffnen. Bis Chrome 83 konnten Entwickler beim Starten eines benutzerdefinierten Tabs beliebige Header hinzufügen. Ab Version 83 filtert Chrome alle ursprungsübergreifenden Header mit Ausnahme von approvelisted, da nicht auf der Genehmigungsliste stehende Header ein Sicherheitsrisiko darstellen. Ab Chrome 86 ist es möglich, nicht auf der Genehmigungsliste stehende Header an ursprungsübergreifende Anfragen anzuhängen, wenn Server und Client über einen Digital Asset Link miteinander verknüpft sind. Dieses Verhalten ist in der folgenden Tabelle zusammengefasst:

Chrome-Version Zulässige CORS-Header
Vor Chrome 83 auf der Zulassungsliste, nicht auf der Zulassungsliste
Chrome 83 bis Chrome 85 Auf der Zulassungsliste
ab Chrome 86 „auf der Zulassungsliste“ oder „nicht auf der Zulassungsliste“, wenn ein Link zu einem digitalen Asset eingerichtet ist

Tabelle 1: Filterung von nicht auf der Zulassungsliste stehenden CORS-Headern.

In diesem Artikel wird beschrieben, wie Sie eine bestätigte Verbindung zwischen dem Server und dem Client einrichten und diese verwenden, um zugelassene und nicht zugelassene HTTP-Header zu senden. Den Code finden Sie unter Benutzerdefinierten Tab-Intents zusätzliche Header hinzufügen.

Hintergrund

CORS-Anfrageheader auf der Genehmigungsliste im Vergleich zu CORS-Anfrageheadern, die nicht auf der Genehmigungsliste stehen

Cross-Origin Resource Sharing (CORS) ermöglicht es einer Webanwendung mit einem Ursprung, Ressourcen eines anderen Ursprungs anzufordern. Die Liste der CORS-approvelisted-Header wird im HTML-Standard verwaltet. Beispiele für genehmigte Header finden Sie in der folgenden Tabelle:

Header Beschreibung
accept-language Werbung für natürliche Sprachen, die der Kunde versteht
content-language beschreibt die Sprache, die für die aktuelle Zielgruppe vorgesehen ist
content-type gibt den Medientyp der Ressource an

Tabelle 2: Beispiel für genehmigte CORS-Header.

Die auf der Genehmigungsliste stehenden Headern gelten als sicher, da sie keine sensiblen Nutzerinformationen enthalten und es unwahrscheinlich ist, dass der Server dadurch potenziell schädliche Vorgänge ausführt.

In der folgenden Tabelle finden Sie Beispiele für nicht genehmigte Header:

Header Beschreibung
bearer-token Authentifizierung des Clients bei einem Server
origin Gibt den Ursprung der Anfrage an.
Cookie Enthält vom Server gesetzte Cookies

Tabelle 3: Beispiel für nicht auf der Genehmigungsliste stehende CORS-Header.

Das Anhängen von nicht auf der Genehmigungsliste stehenden Headern an CORS-Anfragen wird vom HTML-Standard nicht empfohlen. Server gehen davon aus, dass ursprungsübergreifende Anfragen nur Header enthalten, die auf der Genehmigungsliste stehen. Wenn nicht genehmigte Header von domänenübergreifenden Domains gesendet werden, könnten schädliche Drittanbieter-Apps Header erstellen, die Nutzer-Cookies missbrauchen, die von Chrome (oder einem anderen Browser) gespeichert und an Anfragen angehängt werden. Die Cookies könnten bösartige Servertransaktionen authentifizieren, die sonst nicht möglich wären.

CORS-genehmigte Header an Custom Tabs-Anfragen anhängen

Benutzerdefinierte Tabs sind eine spezielle Möglichkeit, Webseiten in einem benutzerdefinierten Browsertab zu öffnen. Benutzerdefinierte Tabs können mit CustomTabsIntent.Builder() erstellt werden. Sie können diesen Intents auch Header hinzufügen. Verwenden Sie dazu ein Bundle mit dem 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"));

Wir können immer genehmigte Header an CORS-Anfragen für benutzerdefinierte Tabs anhängen. Chrome filtert jedoch standardmäßig Header, die nicht auf der Genehmigungsliste stehen. Auch wenn sich andere Browser möglicherweise anders verhalten, sollten Entwickler davon ausgehen, dass Header, die nicht auf der Genehmigungsliste stehen, generell blockiert werden.

Die unterstützte Methode zum Einbinden von Headern, die nicht auf der Genehmigungsliste stehen, in benutzerdefinierte Tabs besteht darin, zuerst die ursprungsübergreifende Verbindung über einen Digital Access Link zu bestätigen. Im nächsten Abschnitt erfahren Sie, wie Sie diese einrichten und einen Custom Tabs-Intent mit den erforderlichen Headern starten.

Zusätzliche Header zu benutzerdefinierten Tab-Intents hinzufügen

Damit nicht auf der Genehmigungsliste stehende Header über Custom Tab-Intents weitergegeben werden können, muss eine Digital Asset Link zwischen der Android- und der Webanwendung eingerichtet werden, die bestätigt, dass der Autor beide Anwendungen besitzt.

Folgen Sie der offiziellen Anleitung, um eine Verknüpfung für digitale Assets einzurichten. Verwenden Sie für die Linkbeziehung „delegate_permission/common.use_as_origin“, um anzugeben, dass beide Apps nach der Bestätigung des Links zum selben Ursprung gehören.

Benutzerdefinierten Tab-Intent mit zusätzlichen Headern erstellen

Es gibt mehrere Möglichkeiten, eine Custom Tabs-Absicht zu erstellen. Sie können den in AndroidX verfügbaren Builder verwenden, indem Sie die Bibliothek zu den Build-Abhängigkeiten hinzufügen:

implementation 'androidx.browser:browser:1.2.0'

Erstellen Sie die Intention und fügen Sie zusätzliche Header hinzu:

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;
}

Eine Custom Tabs-Verbindung wird verwendet, um eine CustomTabsSession zwischen der App und dem Chrome-Tab einzurichten. Wir benötigen die Sitzung, um zu überprüfen, ob die App und die Web-App zum selben Ursprung gehören. Die Überprüfung ist nur erfolgreich, wenn die Links zu digitalen Assets richtig eingerichtet wurden.

Wir empfehlen, CustomTabsClient.warmup() anzurufen. Dadurch kann die Browseranwendung im Hintergrund vorinitialisiert werden, was das Öffnen von URLs beschleunigt.

// 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) { }
};

Callback einrichten, der den Intent nach der Validierung startet

Die CustomTabsCallback wurde in die Sitzung übergeben. Wir richten die onRelationshipValidationResult() so ein, dass die zuvor erstellte CustomTabsIntent gestartet wird, sobald die Ursprungsbestätigung erfolgreich ist.

// 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));
    }
};

Benutzerdefinierte Tabs-Dienstverbindung binden

Durch das Binden des Dienstes wird der Dienst gestartet und die onCustomTabsServiceConnected() der Verbindung wird schließlich aufgerufen. Vergessen Sie nicht, die Bindung des Dienstes entsprechend aufzuheben. Das Binden und Lösen der Bindung erfolgt in der Regel in den Methoden des Aktivitätslebenszyklus onStart() und 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);

Democode für die Anwendung

Weitere Informationen zum Dienst für benutzerdefinierte Tabs Ein funktionierendes Beispiel für eine App finden Sie im GitHub-Repository android-browser-helper.

Zusammenfassung

In diesem Leitfaden wird gezeigt, wie beliebige Header zu CORS-Anfragen für benutzerdefinierte Tabs hinzugefügt werden. Genehmigte Header können an jede CORS-Anfrage für benutzerdefinierte Tabs angehängt werden. Header, die nicht auf der Allowlist stehen, gelten in CORS-Anfragen im Allgemeinen als unsicher und werden von Chrome standardmäßig gefiltert. Das Anhängen ist nur für Clients und Server desselben Ursprungs zulässig, die durch einen Digital Asset Link verifiziert wurden.