User-Agent Client Hints API によるユーザーのプライバシーとデベロッパー エクスペリエンスの向上

User-Agent Client Hints は、Client Hints API の新しい拡張機能です。これにより、デベロッパーはプライバシーを保護し、使いやすい方法でユーザーのブラウザに関する情報にアクセスできます。

Client Hints を使用すると、デベロッパーは User-Agent(UA)文字列から解析するのではなく、ユーザーのデバイスや状態に関する情報を能動的にリクエストできます。この代替ルートを提供する方法は、最終的にユーザー エージェント文字列の粒度を下げる最初のステップです。

User-Agent 文字列の解析に依存する既存の機能を更新して、代わりに User-Agent Client Hints を使用する方法を学びます。

背景

ウェブブラウザがリクエストを行うと、ブラウザとその環境に関する情報が含まれるため、サーバーは分析を有効にしてレスポンスをカスタマイズできます。これは 1996 年に定義されました(HTTP/1.0 の RFC 1945)。ここでは、User-Agent 文字列の元の定義(例を含む)を確認できます。

User-Agent: CERN-LineMode/2.15 libwww/2.17b3

このヘッダーは、重要度の高い順に、プロダクト(ブラウザやライブラリなど)とコメント(バージョンなど)を指定することを目的としていました。

User-Agent 文字列の状態

その後の数十年の間に、この文字列にはリクエストを送信したクライアントに関するさまざまな詳細情報が追加され(下位互換性のために不要な情報も追加されました)、Chrome の現在のユーザー エージェント文字列を見ると、次のことがわかります。

Mozilla/5.0 (Linux; Android 10; Pixel 3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4076.0 Mobile Safari/537.36

上記の文字列には、ユーザーのオペレーティング システムとバージョン、デバイスモデル、ブラウザのブランドと完全バージョンに関する情報が含まれています。また、モバイル ブラウザだと推測できる十分な手がかりのほか、過去の経緯から他のブラウザへの参照が多数含まれています。

これらのパラメータと、想定される値の多様性により、User-Agent 文字列には、個々のユーザーを一意に識別できる十分な情報が含まれる可能性があります。

User-Agent 文字列は、多くの正当なユースケースを実現し、デベロッパーとサイト所有者にとって重要な目的を果たします。ただし、ユーザーのプライバシーを秘密のトラッキング方法から保護することも重要です。デフォルトで UA 情報を送信することは、その目標に反しています。

また、User-Agent 文字列に関しては、ウェブの互換性を改善する必要もあります。構造化されていないため、解析すると不要な複雑さが発生し、多くの場合、バグやサイトの互換性の問題が発生してユーザーに悪影響を及ぼします。また、サイトがその構成に対してテストに失敗している可能性があるため、これらの問題は、あまり一般的でないブラウザのユーザーに不当に不利益をもたらします。

新しい User-Agent Client Hints のご紹介

User-Agent Client Hints を使用すると、同じ情報にアクセスできますが、プライバシーを保護する方法でアクセスできます。これにより、ブラウザは最終的に、すべてをブロードキャストする User-Agent 文字列のデフォルトを削減できます。Client Hints は、サーバーがブラウザにクライアントに関する一連のデータ(ヒント)を要求し、ブラウザが独自のポリシーまたはユーザー設定を適用して、返されるデータを決定するモデルを適用します。つまり、ユーザー エージェント情報をデフォルトですべて公開するのではなく、明示的で監査可能な方法でアクセスが管理されるようになりました。デベロッパーにとっても、正規表現が不要になるなど、API がシンプルになります。

現在のところ、Client Hints は主にブラウザの表示機能と接続機能について説明しています。詳細については、クライアント ヒントによるリソース選択の自動化をご覧ください。ここでは、このプロセスについて簡単に説明します。

サーバーはヘッダーを介して特定の Client Hints をリクエストします。

⬇️ サーバーからのレスポンス

Accept-CH: Viewport-Width, Width

または、メタタグを使用します。

<meta http-equiv="Accept-CH" content="Viewport-Width, Width" />

ブラウザは、後続のリクエストで次のヘッダーを返すことを選択できます。

😝?️ その後のリクエスト

Viewport-Width: 460
Width: 230

サーバーは、適切な解像度で画像を提供するなど、レスポンスの変更を選択できます。

User-Agent Client Hints は、Accept-CH サーバー レスポンス ヘッダーで指定できる Sec-CH-UA 接頭辞を使用してプロパティの範囲を拡張します。詳細については、説明から始め、提案書全体をご覧ください。

Chromium の User-Agent Client Hints API 89

User-Agent Client Hints は、Chrome バージョン 89 以降ではデフォルトで有効になっています。

デフォルトでは、ブラウザはブラウザのブランド、重要なバージョン / メジャー バージョン、プラットフォーム、クライアントがモバイル デバイスかどうかを示すインジケーターを返します。

⬆️ すべてのリクエスト

Sec-CH-UA: "Chromium";v="93", "Google Chrome";v="93", " Not;A Brand";v="99"
Sec-CH-UA-Mobile: ?0
Sec-CH-UA-Platform: "macOS"

User-Agent レスポンスとリクエストのヘッダー

⬇️ レスポンス Accept-CH
Ъ️ リクエスト ヘッダー
📊?️ リクエスト
値の例
説明
Sec-CH-UA "Chromium";v="84",
"Google Chrome";v="84"
ブラウザのブランドと重要なバージョンのリスト。
Sec-CH-UA-Mobile ?1 ブラウザがモバイル デバイス上にあるかどうかを示すブール値(true の場合は ?1、false の場合は ?0)。
Sec-CH-UA-Full-Version "84.0.4143.2" [非推奨]ブラウザの完全版。
Sec-CH-UA-Full-Version-List "Chromium";v="84.0.4143.2",
"Google Chrome";v="84.0.4143.2"
ブラウザのブランドとその完全版のリスト。
Sec-CH-UA-Platform "Android" デバイスのプラットフォーム(通常はオペレーティング システム(OS))。
Sec-CH-UA-Platform-Version "10" プラットフォームまたは OS のバージョン。
Sec-CH-UA-Arch "arm" デバイスの基盤となるアーキテクチャ。これはページの表示とは無関係かもしれませんが、デフォルトで適切なフォーマットでダウンロードできるページを表示したい場合もあるでしょう。
Sec-CH-UA-Model "Pixel 3" デバイスのモデル。
Sec-CH-UA-Bitness "64" 基盤となるアーキテクチャのビット数(整数またはメモリアドレスのビット数)

交換の例

やり取りの例は次のようになります。

✱️ ブラウザからの最初のリクエスト
ブラウザがサイトから /downloads ページをリクエストし、デフォルトのベーシック ユーザー エージェントを送信します。

GET /downloads HTTP/1.1
Host: example.site

Sec-CH-UA: "Chromium";v="93", "Google Chrome";v="93", " Not;A Brand";v="99"
Sec-CH-UA-Mobile: ?1
Sec-CH-UA-Platform: "Android"

⬇️ サーバーからのレスポンス
サーバーはページを返送し、ブラウザの完全なバージョンとプラットフォームをさらに要求します。

HTTP/1.1 200 OK
Accept-CH: Sec-CH-UA-Full-Version-List

⬆️ 後続のリクエスト
ブラウザはサーバーに追加情報へのアクセス権を付与し、後続のすべてのリクエストで追加のヒントを送り返します。

GET /downloads/app1 HTTP/1.1
Host: example.site

Sec-CH-UA: " Not A;Brand";v="99", "Chromium";v="98", "Google Chrome";v="98"
Sec-CH-UA-Mobile: ?1
Sec-CH-UA-Full-Version-List: " Not A;Brand";v="99.0.0.0", "Chromium";v="98.0.4738.0", "Google Chrome";v="98.0.4738.0"
Sec-CH-UA-Platform: "Android"

JavaScript API

ヘッダーに加えて、User-Agent には JavaScript で navigator.userAgentData を介してアクセスすることもできます。デフォルトの Sec-CH-UASec-CH-UA-MobileSec-CH-UA-Platform ヘッダー情報には、それぞれ brands プロパティと mobile プロパティからアクセスできます。

// Log the brand data
console.log(navigator.userAgentData.brands);

// output
[
  {
    brand: 'Chromium',
    version: '93',
  },
  {
    brand: 'Google Chrome',
    version: '93',
  },
  {
    brand: ' Not;A Brand',
    version: '99',
  },
];

// Log the mobile indicator
console.log(navigator.userAgentData.mobile);

// output
false;

// Log the platform value
console.log(navigator.userAgentData.platform);

// output
"macOS";

追加の値には、getHighEntropyValues() 呼び出しを介してアクセスします。「高エントロピー」という用語は、情報エントロピー、つまり、これらの値がユーザーのブラウザについて明らかにする情報量を指しています。追加ヘッダーのリクエストと同様に、どの値が返されるかはブラウザによって異なります。

// Log the full user-agent data
navigator
  .userAgentData.getHighEntropyValues(
    ["architecture", "model", "bitness", "platformVersion",
     "fullVersionList"])
  .then(ua => { console.log(ua) });

// output
{
   "architecture":"x86",
   "bitness":"64",
   "brands":[
      {
         "brand":" Not A;Brand",
         "version":"99"
      },
      {
         "brand":"Chromium",
         "version":"98"
      },
      {
         "brand":"Google Chrome",
         "version":"98"
      }
   ],
   "fullVersionList":[
      {
         "brand":" Not A;Brand",
         "version":"99.0.0.0"
      },
      {
         "brand":"Chromium",
         "version":"98.0.4738.0"
      },
      {
         "brand":"Google Chrome",
         "version":"98.0.4738.0"
      }
   ],
   "mobile":false,
   "model":"",
   "platformVersion":"12.0.1"
}

デモ

ヘッダーと JavaScript API の両方を、user-agent-client-hints.glitch.me でご利用のデバイスで試すことができます。

ヒントの有効期間とリセット

Accept-CH ヘッダーを介して指定されたヒントは、ブラウザのセッション中、または別のヒントセットが指定されるまで送信されます。

つまり、サーバーが次のように送信した場合:

⬇️ レスポンス

Accept-CH: Sec-CH-UA-Full-Version-List

ブラウザが閉じられるまで、ブラウザはそのサイトのすべてのリクエストで Sec-CH-UA-Full-Version-List ヘッダーを送信します。

⬆️ 後続のリクエスト

Sec-CH-UA-Full-Version-List: " Not A;Brand";v="99.0.0.0", "Chromium";v="98.0.4738.0", "Google Chrome";v="98.0.4738.0"

ただし、別の Accept-CH ヘッダーが受信されると、ブラウザが送信している現在のヒントが完全に置き換えられます

⬇️ レスポンス

Accept-CH: Sec-CH-UA-Bitness

⬆️ 後続のリクエスト

Sec-CH-UA-Platform: "64"

以前にリクエストした Sec-CH-UA-Full-Version-List送信されません

Accept-CH ヘッダーは、そのページに必要なヒントの完全なセットを指定すると考えるのがよいでしょう。つまり、ブラウザは、そのページ上のすべてのサブリソースに対して指定されたヒントを送信します。ヒントは次回のナビゲーションに引き続き表示されますが、ヒントが配信されることをサイトで認識したり、信頼したりしてはいけません。

また、レスポンスで空の Accept-CH を送信することで、ブラウザから送信されるすべてのヒントを効果的に消去することもできます。ユーザーが設定をリセットしたり、サイトからログアウトしたりする場所に追加することを検討してください。

このパターンは、<meta http-equiv="Accept-CH" …> タグ経由でヒントが機能する仕組みとも一致します。リクエストされたヒントは、ページによって開始されたリクエストでのみ送信され、その後のナビゲーションでは送信されません。

ヒントのスコープとクロスオリジン リクエスト

デフォルトでは、クライアント ヒントは同一オリジンのリクエストでのみ送信されます。つまり、https://example.com に関する特定のヒントをリクエストしても、最適化したいリソースが https://downloads.example.com にある場合、ヒントは受信されません

クロスオリジン リクエストでヒントを許可するには、各ヒントとオリジンを Permissions-Policy ヘッダーで指定する必要があります。これを User-Agent Client Hints に適用するには、ヒントを小文字にし、sec- 接頭辞を削除する必要があります。例:

⬇️ example.com からのレスポンス

Accept-CH: Sec-CH-UA-Platform-Version, DPR
Permissions-Policy: ch-ua-platform-version=(self "downloads.example.com"),
                    ch-dpr=(self "cdn.provider" "img.example.com");

⬆️ downloads.example.com へのリクエスト

Sec-CH-UA-Platform-Version: "10"

⬆️ cdn.provider または img.example.com へのリクエスト

DPR: 2

User-Agent Client Hints を使用する場所

簡単に答えられるのは、User-Agent ヘッダーを解析している場合や、同じ情報にアクセスする JavaScript 呼び出し(navigator.userAgentnavigator.appVersionnavigator.platform など)を使用しているインスタンスをリファクタリングして、User-Agent Client Hints を使用できるようにすることです。

さらに一歩進んで、User-Agent 情報の使用を再検討し、可能な限り他の方法に置き換える必要があります。多くの場合、プログレッシブ エンハンスメント、機能検出、レスポンシブ デザインを利用することで、同じ目標を達成できます。User-Agent データに依存する基本的な問題は、検査対象のプロパティと、そのプロパティが有効にする動作との間のマッピングを常に維持する必要があることです。検出が包括的で最新の状態を維持するために、メンテナンス オーバーヘッドが発生します。

これらの注意事項を念頭に置き、User-Agent Client Hints リポジトリにサイトの有効なユースケースがいくつか記載されています

User-Agent 文字列はどうなりますか?

既存のサイトに過度の混乱を招くことなく、既存の User-Agent 文字列で公開される識別情報の量を減らすことで、ウェブ上の秘密裏なトラッキングを最小限に抑えることが計画されています。User-Agent Client Hints の導入により、User-Agent 文字列に変更を加える前に、新しい機能を理解してテストできるようになりました。

最終的には、User-Agent 文字列の情報が削減され、従来の形式を維持しながら、デフォルトのヒントと同じ高レベルのブラウザと重要なバージョン情報のみが提供されるようになります。Chromium では、エコシステムが User Agent Client Hints の新しい機能を評価する時間を確保するため、この変更は少なくとも 2022 年まで延期されました。

Chrome 93 から about://flags/#reduce-user-agent フラグを有効にすると、このバージョンをテストできます(注: Chrome 84 ~ 92 のバージョンでは、このフラグは about://flags/#freeze-user-agent という名前でした)。互換性のため、履歴エントリを含む文字列が返されますが、詳細はサニタイズされます。たとえば、次のような内容です。

Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.0.0 Mobile Safari/537.36

サムネイル: UnsplashSergey Zolkin