SafariのUA文字列が固定されて固定されなくなったおはなし

Jxckが以前、SafariUA文字列が固定されたというのを書いていた。

Safari Technology Preview 46で入った変更だ。

Froze the user-agent string to reduce web compatibility risk and to prevent its use for fingerprinting

TwitterでもAppleRicky Mondelloがそれを伝えていて、ちょっと騒ぎになっていた。「それは困る」的な反応が結構多かったのと、中には「やっぱりSafariは新たなIE6だ」みたいな、リスペクトのない反応もちらほら。なんだかね……


さて、これだけだったらここで書くことはなにもないんだけど、続きがある。その後この固定化はとりやめられたのだった。

現在はUA文字列に含まれていたOSのバージョンが固定されず、ちゃんと実際のバージョンを反映するようになっている。先日リリースされたSafari 11.1でもUA文字列の変更については述べているものの、固定という表現ではなくなった。

Updated the User-Agent String Policy

  • Changed the updating policy to to only continue updating the OS version number and Safari version number.

参考までに、手元のmacOS 10.13.4で確認した、Safari 11.1のUA文字列を。

Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/11.1 Safari/605.1.15 

以下はUA文字列固定の経緯と、再度変更されるまでの流れ。

UA文字列の固定とはなんだったのか

RickyのツイートやSTP 46のリリースノートだけだと詳細がわからないが、ちゃんとコミットがある。

Freeze the version reported as User Agent to OS 10.13.4 (OS 11.3 on iOS) and WebKit 605.1.15 for User Agent purposes.

macOSのバージョンが10.13(High Sierra)以降の場合は10_13_4iOSの場合は11_3になると。ついでにWebKitのバージョンも605.1.15に固定される。

なので、パッチが入ったSTP 46からしばらくは、以下のようになっていた。

Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/11.1 Safari/605.1.15

STP 46の時点ではmacOSは10.13.3なので、たしかにOSのバージョンが固定されている感じなのがわかる。

変更の理由

STPのリリースノートにもフィンガープリンティングを避けるという目的が書いてあったけど、該当バグにもう少し細かく書かれていた。

Stop reporting more recent user agent version strings, freezing the version at a specific moment in time. We should do this for a number of reasons:

(1) User Agent sniffing is a terrible way to determine whether a browser supports certain features.

(2) Bad User Agent sniffing code on the web create compatibility problems every time we update the versions.

(3) Overly-specific version information provides useful fingerprinting data while providing almost no user benefit.

  1. ある機能のサポート状況をチェックする方法としてひどい
  2. UA文字列検出のコードがひどいと互換性の問題にバージョンを上げるたびに毎回出くわす
  3. 細かすぎるバージョンの情報はフィンガープリンティングにつながる危険性がある

フィンガープリンティングだけではなくて、UA文字列について一般的に問題とされていることも理由となっていた。

OSのバージョン固定がなくなった

Rickyのツイートにもたくさんの「困る」という声があったし、Appleにそのような声が寄せられたか、はたまた互換性のバグに引っかかったのかわからないけど、件のコミットから2ヶ月ほど経った今年2月、方針が転換されるコミットが入った。

Revert back to dynamically reading the operating system marketing version rather than using a hard-coded version.

OSのバージョンをシステムから読むように(再度)変更したと。つまりは固定されなくなった。

いったん固定するとした方針を軟化させるにあたっては、バグに議論があった。

まずは固定をやめる理由について。

The primary reasons were:

  1. WebKit sometimes ships with bugs that can be worked around at the website level. Having a release version allows websites to activate workarounds where needed.

  2. Decisions about what site content to send to a user agent are often made before the page is loaded. Having UA information when connecting to the server allows websites to send only the relevant payload (e.g., more recent javascript, more efficient image formats, etc.)

  3. Safari (for example) ships with the same version on several operating system revisions. Sometimes bugs exist in specific OS revisions that websites can work around.

For these reasons, we decided to relax some of the restrictions we had originally planned on making.

  1. バグがある状態でリリースされてしまうと、ウェブサイトで対応するしかない。リリースバージョンを含めるを含めることでワークアラウンドが可能になる
  2. ブラウザごとにコンテンツを出し分けるサーバーサイドのコードがあって、UA文字列を含めることで必要なものだけを送れる
  3. SafariはOSといっしょにアップデートされるけど、OSにバグがあるときのワークアラウンドに使える

といった感じ。1、2についてはどのブラウザにも言えるだろうけど、3については半年に一度のリリースで、かつOSとくっついているSafariならではの事情が大きそうだ。

一旦は決めた固定をやめること、そしてその理由については、それはどうなんだという反発もあった。mitz氏はこう問うている。

Shouldn’t WebKit provide a direct and explicit way for websites to determine that a bug is fixed?

バグが直ったら伝える仕組みを設けるべきではという。ドキュメンテーションよりも直接的なものを想定しているのかな。とはいえ、だいぶ理想を見ているようにも見える。そういうのがあってうまく機能したなら、世の中はXMLベースになっていたんじゃないかな。

UA文字列という手段を使い続けることについても、別の方法がないのかという疑問も提示している。

Aren’t there other request headers dedicated to explicitly, directly conveying what the user agent supports?

Client Hintsみたいなものの機能版という感じかな。ヘッダではないけどhasFeature()というものがあって、これはなかなか残念な結果だったはずなので、ヘッダにあってもあまりうまく機能しない気がする。「サポートしている」の粒度が人によってそれぞれ違うだろうから、うまく満たせる仕組みはつくれないだろう。

とまあ、疑問が投げられたけど結局コミットされたので、使えるUA文字列が復活した。めでたいのか、めでたくないのか。


なお、OSのバージョンは固定されなくなったが、WebKitのバージョンは605.1.15に固定されたままだ。WebKitのバージョンでなにかしたいケースってあるかな……ほしいのはOSバージョンだろうから、こいつはそこまで気にされないかなーと思う。

おまけ:なんでアンダースコアで区切ってるのか

OSのバージョンはなぜだか10_13_4と、アンダースコア区切りになっている。

なんかあったのかなーと思ったら、UserAgentCocoa.mmというファイルにこんなコメントが書いてあった。

// Use underscores instead of dots because when we first added the Mac OS X version to the user agent string
// we were concerned about old DHTML libraries interpreting "4." as Netscape 4. That's no longer a concern for us
// but we're sticking with the underscores for compatibility with the format used by older versions of Safari.

OSのバージョンをUA文字列にぶっこんだときに、4.という文字列が現れたら問答無用でNetscape 4と認識するDHTMLライブラリに出会ったらしくそれを迂回する目的だったらしい。たしかにNetscape Communicator時代は4.0とか4.5とか4.7とかマイナーバージョンが更新されたから、4.でマッチさせるようにしたのかな。たしかにNetscapeはいまと比べてUA文字列だいぶ短かったし。

うーんでも、4.でマッチするならIEもマッチする気がするんだけどな……

コミットを探したらあった。

Added Mac OS X version string, right after the string "Mac OS X", but with underscores instead of dots to avoid the dreaded "4." problem (old libraries that think a "4." anywhere in the user agent means Netscape 4).

No way to detect Tiger vs Leopard from Safari's user agent stringと、TigerLeopardを判別したいなにかがあったらしい。なのでOSのバージョンを入れたのだけど、4.が問題になった過去の問題をふまえてアンダースコアにしたと。

ではその4.についての言及はどれかなーとさらに探したら、これまたあった。ちゃんとchangelog書いてるのすごいなー

Adds a build phase script that ensures WebKit's version dosen't end in a 4. If our version ends in 4, some sites might think we are Netscape 4 in their user agent checks.

これを読むと4.ではなく4な気がするんだけど、いつのまにか4.になってるのはどうしてなんだろう。もうわかることはないんだろうけど。

元のコメントを読むと、現在はドットにしたところで互換性の問題はないらしいが、逆に過去のSafariとの互換性がとれなくなるという話でアンダースコアが残されているらしい。ふしぎなコードとバグと互換性でウェブは続いていく。