これはドリコム Advent Calendar 2021の18日目です。
17日目はハヤブサさんの闇の錬金術~Elixirよもやま話~です。

はじめに

こんにちは、enza サーバーサイドエンジニアの小林です。
新卒2年目として、ゲームプラットフォームの開発に携わっています。

Web システム開発をする際、User-Agent を利用して、ユーザーの OS やブラウザ判定などを行っているかと思います。 User-Agent は、2020年1月に削減されることが発表されましたが2021年まで延期となっていました。そして、今年に入り、再度 User-Agent 削減の計画が動き出しています。

そこで、User-Agent 削減の動向とその代わりとして提案されている User Agent Client Hints (UA-CH)について Google Chrome を中心に調査した結果をまとめたいと思います。2021年にも更新があったため、2021年最新の更新情報も含めて話していきたいと思います。

※ 開発中の機能のため、2021年12月段階の内容になります。

そもそも、なぜ User-Agent は削減されるのか

User-Agent は、過去数十年に渡って、リクエストを実行するクライアントに関する様々な情報が追加されてきました。これらのパラメータの組み合わせは、ユーザーを一意に識別できるだけの情報を持っており、フィンガープリントに利用される可能性がありました。また、User-Agent 文字列は構造化が成されておらず、解析は複雑なものとなり、バグの原因となっていました。そのような理由から User-Agent の削減が計画されました。

そこで、開発者にもユーザーにも優しい形で提供できるようするため、User Agent Client Hints が提案されました。

※ 現在は、User-Agent の削減として計画されていますが、UA-CH Github FAQ で単一の静的文字列に凍結する可能性も示唆させています。(すぐ凍結されるわけでは無さそうですが…)

User-Agent 文字列削減計画の変遷

冒頭で触れましたが、一度削減計画が延期されました。今までの流れをまとめると、このようになります。

・ 2020年1月 User-Agent 文字列を非推奨とし、段階的に更新をやめる計画を発表
・ 2020年4月 COVID-19 が影響し、Webエコシステムに追加の移行負担がかからないように延期を発表
・ 2021年5月 User-Agent 文字列削減の計画を再開する方針を発表 (Chromiumブログ)
・ 2021年9月 削減計画のタイムラインを発表 (Chromiumブログ)

User-Agent の削減スケジュール

今年の9月に User-Agent 削減の7つのフェーズとそれを適用予定の Chrome のバージョンが発表されました。(Chromium ブログ)
Chrome バージョンのスケジュールが発表されているため、それと照らし合わせることで具体的にいつまでに対応しないといけないか見えてくるかと思います。
2021年12月現在はフェーズ2であり、削減された User-Agent をテストできるオリジントライアルが行われています。トライアルに申し込むことで、事前にサイトで検証をすることができます。
また、実際の削減策の実施は、2022年の4月の Chrome 101 から始まります。フェーズ4ではメジャーバージョン以外が0に固定されるため、マイナーバージョンなどを使用している場合、対応が必要になります。

User Agent Client Hints (UA-CH) について

上記で説明したような理由から User-Agent の削減が計画され、User Agent Client Hints (以降、UA-CH )が提案されました。そのため、UA-CH は、User-Agent 文字列の粒度を低下させるための第一歩と言われています。方針として UA-CH は、すべての User-Agent 情報をデフォルトで公開するのではなく、サーバーが必要な情報をリクエストします。 UA-CH は、Chrome 89 に機能として追加されているため、ブラウザのデベロッパーツールの network を開き、リクエストヘッダを確認することで実際の値が確認できます。

UA-CH の取得手順

1. ブラウザーからの初回リクエスト
リクエストヘッダにデフォルトで含まれる UA-CH が付与される
(デフォルト: sec-ch-uasec-ch-ua-mobilesec-ch-ua-platform )

[Request Header]
sec-ch-ua: " Not A;Brand";v="99", "Chromium";v="96", "Google Chrome";v="96"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "macOS"

2. サーバーからのレスポンス
レスポンスヘッダーに要求する Client Hints を定義する

[Response Header]
Accept-CH: Sec-CH-UA-Model, Sec-CH-UA-Platform-Version

3. ブラウザーからの2回目以降のリクエスト
サーバーから要求されたSec-CH-UA-Model, Sec-CH-UA-Platform-Versionをリクエストヘッダに含めて送信する

[Request Header]
sec-ch-ua: " Not A;Brand";v="99", "Chromium";v="96", "Google Chrome";v="96"
sec-ch-ua-mobile: ?0
sec-ch-ua-model: ""
sec-ch-ua-platform: "macOS"
sec-ch-ua-platform-version: "11.4.0"

取得可能な項目

Sec-CH-UA
User-Agent に関連付けられたブランド(“Chromium”, “Google Chrome”など)とそのメジャーバージョンのリスト
例: Sec-CH-UA: " Not A;Brand";v="99", "Chromium";v="96", "Google Chrome";v="96"

Sec-CH-UA-Arch
User-Agent の基盤となる CPU アーキテクチャ(”ARM”や”x86″など)
x86CPUアーキテクチャ=> “x86”, ARMCPUアーキテクチャ=> “arm”
例: Sec-CH-UA-Arch: "x86"

Sec-CH-UA-Bitness
User-Agentの基盤となる CPU アーキテクチャのビット数(”32”や”64”など)
例: Sec-CH-UA-Bitness: "64"

Sec-CH-UA-Mobile
デバイスがモバイルデバイスであるかどうかを示すブール値(?0または?1)
例: Sec-CH-UA-Mobile: ?0

Sec-CH-UA-Model
デバイスモデル(例: “” や “Pixel 2 XL” など)モバイルでない場合、空文字列が返ります
例: Sec-CH-UA-Model: "Pixel 2 XL"

Sec-CH-UA-Platform
実行されている OS に関する情報
(“Android”, “Chrome OS”, “iOS”, “Linux”, “macOS”, “Windows”, “Unknown”)
例: Sec-CH-UA-Platform: "macOS"

Sec-CH-UA-Platform-Version
実行されている OS のバージョン
例(macOS Big Sur 11.4): Sec-CH-UA-Platform-Version: "11.4.0"

Sec-CH-UA-Full-Version
ブラウザのフルバージョン
非推奨とされており、将来削除される予定です。
Sec-CH-UA-Full-Version-List に置き換えることが推奨されています。
例: Sec-CH-UA-Full-Version: "96.0.4664.110"

Sec-CH-UA-Full-Version-List
各ブラウザのフルバージョン
Chrome 98 でリリースが予定されているようです。
例: Sec-CH-UA-Full-Version-List: "Microsoft Edge"; v="92.0.902.73", "Chromium"; v="92.0.4515.131", "?Not:Your Browser"; v="3.1.2.0"

実際どんな値が返るか試してみたい場合は、user-agent-client-hints.glitch.meを活用することで自分のデバイスで確認することができます。 UA-CH の仕様や詳細については、公式のドキュメントをご確認ください。

User Agent Client Hints (UA-CH)の最近の更新

最近の Chrome の更新にも UA-CH に関連する更新が含まれており、定期的に動向を追っていく必要があります。ここ最近の更新で UA-CH に関連する項目を以下にまとめました。

Chrome 93 リリースノート

User-Agent Client Hints API に新機能を追加 
Chrome 93 では、User-Agent Client Hints API に次の4つの機能が追加されます。
・ Sec-CH-UA-Bitness を追加: プラットフォームのビットを返します。ダウンロード中に最適化されたバイナリを送信する場合などに役立ちます。
・ Sec-CH-UA-Platform を低エントロピー化: デフォルトで送信されます。この変更を行う前は、ヒントをリクエストする必要がありました。
・ UADataValues(getHighEntropyValues() から返される)に低エントロピーのヒントをデフォルトで含める: ヒントを高エントロピー情報から低エントロピー情報にすることで、サイトの互換性の問題を防ぐことができます。
・ toJSON メソッドを NavigatorUAData に追加: {} を返す代わりに、JSON.stringify(navigator.userAgentData) を使用できるようになりました。

Chrome 93では、User-Agent の基盤となる CPU アーキテクチャのビット数を取得するSec-CH-UA-Bitnessが追加されています。
また、Sec-CH-UA-Platformがデフォルトで送信されるようになりました。(関連 issue)

個人的に、この変更が結構ありがたく、UA-CH によるデバイス判定の実装が楽になりました。
UA-CH によるデバイス判定を考えた時、モバイルかどうかを判定するSec-CH-UA-Mobileと OS 情報に関するSec-CH-UA-Platformを必要とします。 Sec-CH-UA-Mobileは元々デフォルトとして取得できましたが、Sec-CH-UA-Platformを取得するためにリクエストヘッダに Accept-CH を指定して詳細情報を要求する必要があったのです。これにより、初回リクエスト時のデバイス判定どうするかなど考慮するところが多かったのです。 しかし、この更新でデフォルトで判定できるようになったため、新たな Clint Hints の要求や初回リクエストの考慮などが必要なくなったのです。よかった。

Chrome 94 リリースノート

UserAgentClientHintsEnabled ポリシーを削除
UA-CH の hint 内、特に Sec-CH-UA ヘッダーと Sec-CH-UA-Mobile ヘッダーで構造化ヘッダーを使用すると、サーバーによってはすべての文字を認識することができないという、意図しない事象が引き起こされていました。これを無効にするために、UserAgentClientHintsEnabled が作成されましたが、Chrome 94 で削除されます。

UA-CH は、ユーザーのブラウザと環境に関する情報をリクエストヘッダーに載せて送信します。
そのため、リクエストに含める情報を制限している一部のウェブサイトで正常に動作しない可能性がありました。そこで、UA-CH の導入時に一時的な適用を想定した機能として制御機能が用意されていました。
UA-CH 導入から時間が経ったため、削除されることが予告され、Chrome 94 で削除されました。

各ブラウザにおける UA-CH

今回は Google Chrome を中心に見ていきましたが、ブラウザは Chrome だけでないので、他のブラウザも考慮する必要があります。主要なブラウザが UA-CH に対して、どのような方針でいるかまとめます。

Google Chrome
Chrome では、Chrome 89 より UA-CH をサポートされています。
User-Agent の削減計画が発表されており、 削減される User-Agent 文字列の情報を使用してる場合、UA-CH への移行を薦めています。(Google Developers Japan)

Microsoft Edge
Edge では、 Edge バージョン 90から UA-CH をサポートしています。
User-Agent 情報の取得する際に、従来の UA 文字列を使用するのは古く、web サイトの互換性の問題を引き起こした歴史があるため、UA-CH を使用することが推奨されています。
Web サイトから Microsoft Edge を検出する
基本的に、UA-CH の取得方法は、Chrome と変わりません。

現在サポートされていないブラウザ

Safari
safari では、UA-CH をサポートしていないようです。
UA-CH への対応する方針かどうかについては不明でした。
また、safari の User-Agent は、Safari Technology Preview 46 で一度凍結されました。しかし、バグの報告などが上がり、OS バージョンの固定化が廃止になっています。現在は、一部の UA が固定されています。

Firefox
Firefox では、UA-CH をサポートしていないようです。
UA-CH によって新しいヘッダーが送られることでパフォーマンスに影響が出ることを懸念しているようです。また、ヘッダーを追加することでフィールドの制限を越え、将来の仕様に影響が出るかもしれないことを気にしています。 (Github mozilla/standards-positions

終わりに

今回は、削減が計画させている User-Agent とその代替となる User Agent Client Hints についてまとめてみました。延期がされてまだ来ないだろうと思っていた UA 文字列の削減でしたが、 UA 削減スケジュールが改めて発表され、少しずつではありますが、削減が迫ってきましたことを実感しています。
削減予定の UA 文字列を使用した実装がないかを見直して、 UA-CH を用いた実装を検討してみるのは、いかがでしょうか。
また、UA-CH に関しては、今後もアップデートされることが十分考えられるため、リリースノートなどを追って変更を確認する必要がありそうです。



19日目は 中原翼 さんの記事です。

ドリコムでは一緒に働くメンバーを募集しています!
募集一覧はコチラを御覧ください!