/tmp/

雑なメモを置く場所。書いた内容の責任は取らないし、正確性、永続性なども保証しない。

User-Agent Client Hints のメモ

従来の User-Agent の問題

  • 現在の UA は多くの情報が入っており、それをデフォルトで送信することはプライバシーの観点からやめたい
  • パースが複雑になるので、バグの原因となりやすい

User-Agent Client Hints

従来の UA と同じ情報にアクセスにできるようにしつつ、プライバシーの保護や、よりパースをしやすく整備した。 サーバーサイドでは特定のヘッダを、フロントエンドは新しいシンプルな API を使って取得できる。

Chrome 84 以降では chrome://flags/#enable-experimental-web-platform-features を有効にすることで利用できる。

User-Agent Client Hints にデフォルトで含まれるもの

  • Sec-CH-UA ... ブラウザ名と major/significant バージョン
  • Sec-CH-UA-Mobile ... モバイルデバイスかどうか (bool)

仕様の変更は今現在進んでいるので、デフォルトセットに変更があるかも。

これまでの UA の取得方法

  • navigator.userAgent
  • navigator.platform (非推奨)
  • navigator.appVersion (非推奨)
  • User-Agent HTTP ヘッダ

User-Agent Client Hints への移行

前提として Secure Context である必要があるので注意。

フロントエンド

  1. navigator.userAgentData を使う
if (navigator.userAgentData) {
 // use hints
} else {
  // fall back to user-agent string parse
}

navigator.userAgentData はブラウザのブランド名とバージョンをプロパティとして持っている。

> navigator.userAgentData
< NavigatorUAData {brands: Array(3), mobile: false}
    brands: Array(3)
      0: {brand: " Not;A Brand", version: "99"}
      1: {brand: "Google Chrome", version: "91"}
      2: {brand: "Chromium", version: "91"}
        length: 3
      __proto__: Array(0)
      mobile: false
    __proto__: NavigatorUAData

より詳細な情報がほしい場合は navigator.userAgentData.getHighEntroyValues を使う。Promise で返ってくることに注意。

> navigator.userAgentData
.getHighEntropyValues(["architecture", "bitness", "model", "platform", "platformVersion", "uaFullVersion"])
.then(ua => { console.log(ua) });
< Promise {<pending>}
< VM770:3 {architecture: "x86", model: "", platform: "macOS", platformVersion: "10_15_7", uaFullVersion: "91.0.4472.77"}
  1. モバイルの判定には navigrator.userAgentData.mobile を使う
const isMobile = navigator.userAgentData.mobile;

サーバーサイド

User-Agent の代わりに Sec-CH-* ヘッダを見るようにする。Chrome 91.0.4472.77 では、次のような HTTP リクエストヘッダがついている。

sec-ch-ua: " Not;A Brand";v="99", "Google Chrome";v="91", "Chromium";v="91"
sec-ch-ua-mobile: ?0

さらに情報がほしい場合は Accept-CH で指定すると、後続のリクエストから取得できる。

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

もし First リクエストから取得したい場合は Critical-CH ヘッダを使うらしい(試していないので未確認)。Critical-CH ヘッダを使うと、ブラウザはそのヘッダを付けてリクエストをやり直す。

Critical-CHAccept-CH と同じ値を持たなければいけない。

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

Cross Origin リクエストの場合

https://blog.sitehttps://cdn.site のリソースを読み込んでいる場合、https://blog.siteSec-CH-UA-Platform をリクエストして取得できるが、https://cdn.site は取得できない。そのため、Permissions-Policy で明示的に https://cdn.site に委任する必要がある。委任できるリストは https://wicg.github.io/client-hints-infrastructure/#policy-controlled-client-hints-features で確認できる。

iframe の場合

blog.site に次のような iframe を埋め込むと、そのさきの https://widget.siteUH-UA-Model を取得できる。

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

References