Zu User-Agent-Client-Hints migrieren

Strategien zur Migration deiner Website von der Nutzung des User-Agent-Strings zu den neuen User-Agent-Client-Hints

Der User-Agent-String ist eine erhebliche Passiv-Fingerprinting-Oberfläche in Browsern, die schwierig zu verarbeiten ist. Es gibt jedoch viele gute Gründe für die Erfassung und Verarbeitung von User-Agent-Daten. Wir benötigen also einen Pfad zu einer besseren Lösung. User-Agent-Client-Hints bieten sowohl eine explizite Möglichkeit, um die Notwendigkeit von User-Agent-Daten zu deklarieren, als auch Methoden, um die Daten in einem benutzerfreundlichen Format zurückzugeben.

In diesem Artikel erfahren Sie, wie Sie Ihren Zugriff auf User-Agent-Daten prüfen und die Nutzung von User-Agent-Strings zu User-Agent-Client-Hints migrieren.

Erfassung und Verwendung von User-Agent-Daten prüfen

Wie bei jeder Art der Datenerhebung sollten Sie immer verstehen, warum Sie diese erheben. Der erste Schritt besteht darin, zu verstehen, wo und warum Sie User-Agent-Daten verwenden, unabhängig davon, ob Sie etwas unternehmen oder nicht.

Wenn Sie nicht wissen, ob oder wo User-Agent-Daten verwendet werden, sollten Sie in Ihrem Frontend-Code nach navigator.userAgent und im Backend-Code nach dem User-Agent-HTTP-Header suchen. Prüfen Sie außerdem, ob im Frontend-Code bereits eingestellte Funktionen wie navigator.platform und navigator.appVersion verwendet werden.

Aus funktionaler Sicht sollten Sie sich an eine beliebige Stelle in Ihrem Code denken, an der Sie eine Aufzeichnung oder Verarbeitung durchführen:

  • Browsername oder -version
  • Name oder Version des Betriebssystems
  • Marke oder Modell des Geräts
  • CPU-Typ, Architektur oder Bitness (z. B. 64-Bit)

Wahrscheinlich verwendest du zur Verarbeitung des User-Agents auch eine Bibliothek oder einen Drittanbieterdienst. Prüfe in diesem Fall, ob sie aktualisiert werden, um User-Agent-Client-Hints zu unterstützen.

Verwenden Sie nur grundlegende User-Agent-Daten?

Standardmäßig sind folgende User-Agent-Client-Hints verfügbar:

  • Sec-CH-UA: Browsername und Hauptversion/wichtige Version
  • Sec-CH-UA-Mobile: boolescher Wert, der ein Mobilgerät angibt
  • Sec-CH-UA-Platform: Name des Betriebssystems
    • Hinweis: Dies wurde bereits in der Spezifikation aktualisiert und wird bald in Chrome und anderen Chromium-basierten Browsern verfügbar sein.

Die reduzierte Version des vorgeschlagenen User-Agent-Strings behält diese grundlegenden Informationen ebenfalls in abwärtskompatibler Weise bei. Statt Chrome/90.0.4430.85 würde der String beispielsweise Chrome/90.0.0.0 enthalten.

Wenn Sie den User-Agent-String nur auf den Browsernamen, die Hauptversion oder das Betriebssystem prüfen, wird Ihr Code weiterhin funktionieren, auch wenn wahrscheinlich Einstellungswarnungen angezeigt werden.

Obwohl Sie zu User-Agent-Client-Hints migrieren können und sollten, gibt es möglicherweise veraltete Code- oder Ressourceneinschränkungen, die dies verhindern. Durch die auf diese abwärtskompatible Reduzierung der Informationen im User-Agent-String soll sichergestellt werden, dass vorhandener Code zwar weniger detaillierte Informationen erhält, aber die grundlegenden Funktionen beibehalten sollten.

Strategie: Clientseitige JavaScript API auf Abruf

Wenn Sie derzeit navigator.userAgent verwenden, sollten Sie auf navigator.userAgentData übergehen, bevor Sie auf das Parsen des User-Agent-Strings zurückgreifen.

if (navigator.userAgentData) {
  // use new hints
} else {
  // fall back to user-agent string parsing
}

Wenn Sie nach Mobilgeräten oder Computern suchen, verwenden Sie den booleschen Wert mobile:

const isMobile = navigator.userAgentData.mobile;

userAgentData.brands ist ein Array von Objekten mit den Attributen brand und version, aus denen der Browser die Kompatibilität mit diesen Marken auflisten kann. Sie können direkt als Array darauf zugreifen oder mit einem some()-Aufruf prüfen, ob ein bestimmter Eintrag vorhanden ist:

function isCompatible(item) {
  // In real life you most likely have more complex rules here
  return ['Chromium', 'Google Chrome', 'NewBrowser'].includes(item.brand);
}
if (navigator.userAgentData.brands.some(isCompatible)) {
  // browser reports as compatible
}

Wenn Sie einen der detaillierteren User-Agent-Werte mit hoher Entropie benötigen, müssen Sie ihn angeben und im zurückgegebenen Promise nach dem Ergebnis suchen:

navigator.userAgentData.getHighEntropyValues(['model'])
  .then(ua => {
    // requested hints available as attributes
    const model = ua.model
  });

Sie können diese Strategie auch verwenden, wenn Sie von der serverseitigen zur clientseitigen Verarbeitung wechseln möchten. Die JavaScript API benötigt keinen Zugriff auf HTTP-Anfrageheader, sodass User-Agent-Werte jederzeit angefordert werden können.

Strategie: Statischer serverseitiger Header

Wenn Sie den Anfrageheader User-Agent auf dem Server verwenden und Ihre Anforderungen an diese Daten auf der gesamten Website relativ konsistent sind, können Sie die gewünschten Clienthinweise als statischen Satz in Ihren Antworten angeben. Dies ist ein relativ einfacher Ansatz, da Sie ihn in der Regel nur an einem Standort konfigurieren müssen. Sie können sich beispielsweise in Ihrer Webserverkonfiguration befinden, wenn Sie dort bereits Header, in Ihrer Hosting-Konfiguration oder in der Top-Level-Konfiguration des Frameworks oder der Plattform, die Sie für Ihre Website verwenden, hinzugefügt haben.

Sie sollten diese Strategie in Betracht ziehen, wenn Sie die auf der Grundlage der User-Agent-Daten bereitgestellten Antworten transformieren oder anpassen möchten.

Da Browser oder andere Clients unterschiedliche Standardhinweise bereitstellen, empfiehlt es sich, alles Notwendige anzugeben, selbst wenn dies normalerweise standardmäßig der Fall ist.

Die aktuellen Standardeinstellungen für Chrome werden beispielsweise so dargestellt:

⬇️ Antwort-Header

Accept-CH: Sec-CH-UA-Mobile, Sec-CH-UA-Platform, Sec-CH-UA

Wenn Sie das Gerätemodell auch in Antworten erhalten möchten, senden Sie Folgendes:

⬇️ Antwort-Header

Accept-CH: Sec-CH-UA-Mobile, Sec-CH-UA-Model, Sec-CH-UA-Platform, Sec-CH-UA

Bei der serverseitigen Verarbeitung sollten Sie zuerst prüfen, ob der gewünschte Sec-CH-UA-Header gesendet wurde, und dann auf den User-Agent-Header zurückgreifen, falls er nicht verfügbar ist.

Strategie: Hinweise an ursprungsübergreifende Anfragen delegieren

Wenn Sie ursprungsübergreifende oder websiteübergreifende Unterressourcen anfordern, für die User-Agent-Client-Hints für ihre Anfragen gesendet werden müssen, müssen Sie die gewünschten Hinweise mithilfe einer Berechtigungsrichtlinie explizit angeben.

Beispiel: https://blog.site hostet Ressourcen auf https://cdn.site, wodurch Ressourcen zurückgegeben werden können, die für ein bestimmtes Gerät optimiert sind. https://blog.site kann den Sec-CH-UA-Model-Hinweis anfordern, muss ihn aber mithilfe des Permissions-Policy-Headers explizit an https://cdn.site delegieren. Die Liste der richtliniengesteuerten Hinweise ist im Infrastrukturentwurf für Clients verfügbar.

⬇️ Antwort von blog.site, die den Hinweis delegiert

Accept-CH: Sec-CH-UA-Model
Permissions-Policy: ch-ua-model=(self "https://cdn.site")

⬆️ Anfrage an untergeordnete Ressourcen von cdn.site enthält den delegierten Hinweis

Sec-CH-UA-Model: "Pixel 5"

Sie können mehrere Hinweise für mehrere Ursprünge und nicht nur aus dem Bereich ch-ua angeben:

😃️ Antwort von blog.site, bei der mehrere Hinweise an mehrere Ursprünge delegiert werden

Accept-CH: Sec-CH-UA-Model, DPR
Permissions-Policy: ch-ua-model=(self "https://cdn.site"),
                    ch-dpr=(self "https://cdn.site" "https://img.site")

Strategie: Hinweise an iFrames delegieren

Ursprungsübergreifende iFrames funktionieren ähnlich wie ursprungsübergreifende Ressourcen. Allerdings geben Sie die Hinweise, die Sie delegieren möchten, im Attribut allow an.

⬇️ Antwort von blog.site

Accept-CH: Sec-CH-UA-Model

↪️ HTML für blog.site

<iframe src="https://widget.site" allow="ch-ua-model"></iframe>

⬆️ Anfrage an widget.site

Sec-CH-UA-Model: "Pixel 5"

Das Attribut allow im iFrame überschreibt alle Accept-CH-Header, die widget.site möglicherweise selbst sendet. Achte daher darauf, dass du alles angegeben hast, was für die iFrame-Website erforderlich ist.

Strategie: Dynamische serverseitige Hinweise

Wenn Sie in bestimmten Bereichen der User Journey eine größere Auswahl an Hinweisen benötigen als für den Rest der Website, können Sie diese Hinweise bei Bedarf anfordern anstatt statisch für die gesamte Website. Dies ist zwar komplizierter, aber wenn Sie bereits unterschiedliche Header für jede Route festlegen, ist dies möglicherweise möglich.

Denken Sie daran, dass jede Instanz des Accept-CH-Headers den vorhandenen Satz überschreibt. Wenn Sie den Header also dynamisch festlegen, muss jede Seite den vollständigen Satz an erforderlichen Hinweisen anfordern.

Angenommen, du hast einen Abschnitt auf deiner Website, in dem du Symbole und Steuerelemente bereitstellen möchtest, die zum Betriebssystem des Nutzers passen. Dazu können Sie zusätzlich Sec-CH-UA-Platform-Version abrufen, um die entsprechenden Unterressourcen bereitzustellen.

⬇️ Antwort-Header für /blog

Accept-CH: Sec-CH-UA-Mobile, Sec-CH-UA-Platform, Sec-CH-UA

⬇️ Antwort-Header für /app

Accept-CH: Sec-CH-UA-Mobile, Sec-CH-UA-Platform, Sec-CH-UA-Platform-Version, Sec-CH-UA

Strategie: Serverseitige Hinweise bei der ersten Anfrage erforderlich

Es kann vorkommen, dass für die erste Anfrage mehr Hinweise erforderlich sein müssen, als es bei der ersten Anfrage der Fall ist. Dies ist jedoch sehr selten. Lesen Sie die Begründung durch.

Bei der ersten Anfrage handelt es sich tatsächlich um die erste Anfrage der obersten Ebene für diesen Ursprung, die in dieser Browsersitzung gesendet wurde. Die Standardhinweise umfassen den Browsernamen mit Hauptversion, die Plattform und die Anzeige für Mobilgeräte. Die Frage, die Sie sich stellen sollten, lautet also: Sind beim ersten Seitenaufbau erweiterte Daten erforderlich?

Für zusätzliche Hinweise zur ersten Anfrage gibt es zwei Möglichkeiten. Erstens können Sie den Header Critical-CH verwenden. Dieses Format hat das gleiche Format wie Accept-CH, teilt dem Browser aber mit, dass er die Anfrage sofort wiederholen soll, wenn die erste Anfrage ohne den kritischen Hinweis gesendet wurde.

⬆️ Erste Anfrage

[With default headers]

⬇️ Antwort-Header

Accept-CH: Sec-CH-UA-Model
Critical-CH: Sec-CH-UA-Model

🔃 Der Browser wiederholt die ursprüngliche Anfrage mit dem zusätzlichen Header

[With default headers + …]
Sec-CH-UA-Model: Pixel 5

Dies verursacht den Aufwand für Wiederholungsversuche bei der allerersten Anfrage, die Implementierungskosten sind jedoch relativ niedrig. Senden Sie einfach den zusätzlichen Header und der Browser erledigt den Rest.

Wenn Sie wirklich beim ersten Laden der Seite zusätzliche Hinweise benötigen, erstellt das Client Hints Reliability-Angebot eine Route, um Hinweise in den Einstellungen auf Verbindungsebene anzugeben. Dadurch wird die Erweiterung Application-Layer Protocol Settings(ALPS) für TLS 1.3 genutzt, um die frühzeitige Übergabe von Hinweisen bei HTTP/2- und HTTP/3-Verbindungen zu ermöglichen. Dies ist noch ganz am Anfang, aber wenn Sie Ihre eigenen TLS- und Verbindungseinstellungen aktiv verwalten, ist dies ein idealer Zeitpunkt, um einen Beitrag zu leisten.

Strategie: Legacy-Unterstützung

Möglicherweise ist auf deiner Website Legacy- oder Drittanbietercode vorhanden, der von navigator.userAgent abhängig ist. Dazu gehören auch Teile des User-Agent-Strings, die reduziert werden. Langfristig sollten Sie auf die entsprechenden navigator.userAgentData-Aufrufe umstellen, aber es gibt eine Zwischenlösung.

UA-CH retrofill ist eine kleine Bibliothek, mit der Sie navigator.userAgent mit einem neuen String überschreiben können, der aus den angeforderten navigator.userAgentData-Werten erstellt wird.

Dieser Code generiert beispielsweise einen User-Agent-String, der zusätzlich den Hinweis „Modell“ enthält:

import { overrideUserAgentUsingClientHints } from './uach-retrofill.js';
overrideUserAgentUsingClientHints(['model'])
  .then(() => { console.log(navigator.userAgent); });

Der resultierende String würde das Modell Pixel 5 anzeigen, aber weiterhin die reduzierte 92.0.0.0, da der uaFullVersion-Hinweis nicht angefordert wurde:

Mozilla/5.0 (Linux; Android 10.0; Pixel 5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.0.0 Mobile Safari/537.36

Weitere Unterstützung

Wenn diese Strategien für Ihren Anwendungsfall nicht geeignet sind, starten Sie eine Diskussion im Repository „privacy-sandbox-dev-support“, damit wir Ihr Problem gemeinsam untersuchen können.

Foto von Ricardo Rocha auf Unsplash