User-Agent Client Hints は、Client Hints API の新しい拡張です。デベロッパーは、プライバシーを保護し、人間工学に基づいた方法でユーザーのブラウザに関する情報にアクセスできます。
Client Hints を使用すると、デベロッパーは User-Agent(UA)文字列から情報を解析する必要がなくなり、ユーザーのデバイスや状態に関する情報を積極的にリクエストできます。この代替ルートを提供することが、最終的にユーザー エージェント文字列の粒度を下げる最初のステップです。
User-Agent Client Hints の使用に User-Agent 文字列の解析に依存する既存の機能を更新する方法について説明します。
背景情報
ウェブブラウザがリクエストを行うと、サーバーが分析を有効にしてレスポンスをカスタマイズできるように、ブラウザとその環境に関する情報が含まれます。これは 1996 年(HTTP/1.0 については RFC 1945)に定義されています。ここでは、次のようなユーザー エージェント文字列の元の定義を確認できます。
User-Agent: CERN-LineMode/2.15 libwww/2.17b3
このヘッダーは、重要度の高い順にプロダクト(ブラウザやライブラリなど)とコメント(バージョンなど)を指定するためのものです。
ユーザー エージェント文字列の状態
それから 10 年の間に、この文字列はリクエストを行ったクライアントに関するさまざまな詳細情報を獲得してきました(下位互換性があるため)。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 を使用したリソース選択の自動化をご覧ください。ここでは、そのプロセスを簡単に復習します。
サーバーはヘッダーを介して特定の 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
Chrome バージョン 89 以降では、User-Agent Client Hints がデフォルトで有効になっています。
デフォルトでは、ブラウザのブランド、重要なバージョン / メジャー バージョン、プラットフォーム、クライアントがモバイル デバイスかどうかのインジケーターが返されます。
⚈️ すべてのリクエスト
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"
ユーザー エージェントのレスポンスとリクエスト ヘッダー
⬇️ レスポンス Accept-CH descriptions️ リクエスト ヘッダー |
😝?️ リクエスト 値の例 |
説明 |
---|---|---|
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
ページをリクエストし、デフォルトの基本的な User-Agent を送信します。
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
ヘッダーに加えて、JavaScript でも navigator.userAgentData
を使用して User-Agent にアクセスできます。デフォルトの Sec-CH-UA
、Sec-CH-UA-Mobile
、Sec-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"
}
デモ
user-agent-client-hints.glitch.me で、ご自身のデバイスでヘッダーと JavaScript API の両方を試すことができます。
ヒントの有効期間とリセット
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" …>
タグを介したヒントの動作とも一致します。リクエストされたヒントは、ページによって開始されたリクエストでのみ送信され、その後のナビゲーションでは送信されません。
ヒントの範囲とクロスオリジン リクエスト
デフォルトでは、Client Hints は同一オリジンのリクエストでのみ送信されます。つまり、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.userAgent
、navigator.appVersion
、navigator.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
Unsplash の Sergey Zolkin によるサムネイル