[EDIT] 23/03/2020- The blog and the demo were updated according to the new changes implemented on Chrome Canary version 83.0.4093.0.

A few weeks ago, Google announced that the good old user-agent string will be deprecated in Chrome browser later this year.

For those not familiar with the concept, User Agent (UA) is a string that contains information and details about the client’s browser and the platform it’s running on. That information contains the user’s browser software and its version, the operating system, and even the platform architecture and model. The UA is included in every request which gets sent by the browser and dependent on by many sites in various ways and for various purposes. Web applications use it in order to serve the clients the relevant site format, optimized for desktop or mobile devices, and to customize the page content according to the client’s browser and more. In many cases, third-party groups, such as ad-tech companies or security vendors, also use the UA string to fingerprint and track the end-users.

What is this change exactly?

Google’s user-agent phase out is part of the Google Sandbox project, which set a target to strengthen end-users privacy when browsing the internet. It is important to mention here that the UA phase out will not stop or block the ability to track and collect the end-users browser and platform information, but it will make it safer and easier to track.

Google plans to reduce the information that will be stored in the UA string gradually over the next year. At first, on Chrome version 81 (March 2020) Google will start showing console warnings for JavaScript User-Agent access (such as navigator.userAgent). Three months after that, on Chrome version 83, Google will freeze the User-Agent string and will ambiguously specify the OS platform version (specific OS versions won’t be mentioned anymore, so for example Windows 7 and Windows 10 will both be shown just as Windows). Lastly, on Chrome version 85 (September 2020), Google will unify the UA further, to mention just the browser software and device type (for example- Chrome on Desktop, Chrome on Mobile).

Going technically — how to get the missing UA data?

Two different methods will replace the access to the User-Agent string information– the first one will provide a replacement for the User-Agent header and the second to JavaScript’s navigator.userAgent.

[!] As of writing this article, those changes are not implemented by default in Chrome Stable (v79) nor Chrome Canary (v82) versions. In order to enable the changes in your Chrome browser browse to chrome://flags/#enable-experimental-web-platform-features and enable the flag. On the Canary version, you can also enable the chrome://flags/#freeze-user-agent flag. [Edit] 23/03/2020: Currently, the changes are implemented just in the Canary version of Google Chrome.

Header based user-agent replacement

Google Chrome will expose the UA information with Client Hints headers.

The Client Hints mechanism allows websites and web servers to request specific information about the client and the end-user. The web server responds to the client’s requests with “Accept-CH” header, containing the required information as the header value.

The client from its side responds with a “sec-ch-something” header that contains the requested information as the header value. Each information piece will be sent with a different header, where “something” is replaced with the type of information requested (see the examples below).

As opposed to the User-Agent string that gets sent by default with every request and contains all the client’s information, no matter if the server truly needs it or not, the client hints requires the server to actively request this information, which makes it possible for browsers to monitor the servers asking for it.

It is important to mention that those headers are supported only over HTTPS, which makes it more secure and safe.

Additionally, it is must be noted that third-party vendors will have to get a permission from first-party domain owner in order to collect the information. This change have a critical implication on third-party vendors such as security or ad-tech companies which use the User-Agent in order to fingerprint the end-user. The delegation has to be implemented as described here.

Client hints implementation

In order to implement the Client Hints headers, first configure your web server to send to the client an “Accept-CH” header with the exact information you want to collect (see detailed description below). You can also set an “Accept-CH-Lifetime”, which specifies the persistence of the Accept-CH header value for a given number of seconds, so that the client will send the Client Hints to the server for every request made to the same domain, even if the “Accept-CH” header is not sent for every request during this time period.

On the client side, the browser will include “Sec-CH-something” headers that store the information requested by the server.

Accept-CH allowed values

The Accept-CH header accepts the following values: UA, UA-Platform, UA-Arch, UA-Model, UA-Mobile, UA-Full-Version.

Accept-CH: UA- The basic one, asking for the browser software and its version. The response will be sent in a “sec-ch-ua” header.

Accept-CH: UA // Response header

sec-ch-ua: "Google Chrome"; v="83" // Request Header

Accept-CH: UA-Platform- Gives the server information about the platform in which the browser is running on. The response will be sent in a “sec-ch-ua-platform” header.

Accept-CH: UA-Platform // Response header

sec-ch-ua-platform: "Windows"; v="10.0; " // Request header

Accept-CH: UA-Arch- Gives the server information about the platform architecture which the browser is running on. The response will be sent in a “sec-ch-ua-arch” header.

Accept-CH: UA-Arch // Response header

sec-ch-ua-arch: Win64; x64 // Request header

Accept-CH: UA-Model- Gives the server information about the specific device model on which the browser is running on. This one is more relevant to mobile devices. This header is currently supported but may be deleted in the final version of this feature, as Google has not yet decided if providing the exact device model is truly necessary and does not consider as a private information. The response will be sent in a “sec-ch-ua-model” header.

Accept-CH: UA-Model // Response header

sec-ch-ua-model: Pixel 3 // Request header

Accept-CH: UA-Mobile- Indicates if the browser is running on a mobile device or not. The response will be sent in a “sec-ch-ua-mobile” header and will return two values- 1 if the device is a mobile device and “?0” if it’s not.

Accept-CH: UA-Mobile // Response header

sec-ch-ua-mobile: ?0 // Request header

Accept-CH: UA-Full-Version- Returns the browser full version. The response will be sent in a “sec-ch-ua-full-version” header.

Accept-CH: UA-Full-Version // Response header

sec-ch-ua-full-version: "83.0.4092.0" // Request header

Client Hints implementation. First, the server responds with an “Accept-CH” header, then the client attaches the Client Hints headers for every request made to the same domain

JavaScript Interface

In addition to the Client Hints interface, Google Chrome will also provide a JavaScript interface that will expose the user-agent information to client-side JavaScript. The new API will be accessible under the navigator object and will expose the same information as the Client Hints headers.

The new API can be separated for two parts- the first which serves the low entropy values and the second, which serves the high entropy values.

The low entropy values reveal whether the client uses a mobile device or not and the browser brand and its major version. All the other information can be accessed with a new dedicated asynchronous function, named navigator.userAgentData.getHighEntropyValues() which returns a promise. Once the promise is resolved successfully, an object that contains all the relevant information will be returned.

Please note that the JavaScript interface will be accessible just in HTTPS pages, similarly to the Client Hints headers.

Example:

// Low entropy values

navigator.userAgentData.mobile; // false

navigator.userAgentData.uaList; // [{ "brand": "Google Chrome", "version": "83" }] // High entropy values navigator.userAgentData.getHighEntropyValues([

"platform",

"platformVersion",

"architecture",

"model",

"uaFullVersion"

]).then(res => console.log(res)); // Output

{ "architecture":"Win64; x64",

"model":"",

"platform":"Windows",

"platformVersion":"10.0; ",

"uaFullVersion":"83.0.4096.0"

}

Conclusion, notes and demo

The upcoming UA phase out will take place later this year. From my point of view, the user-agent string is an old solution that provides too much information about the end-users by default — but also a foundation stone of today’s internet, where almost every web application relies on it. This change will provide better monitoring abilities, will let us know who is using this information and, in the bottom line, will improve the end-users’ privacy.

Furthermore, security-wise — spoofing the user-agent is currently a very basic and easy method, allowing fraudsters and bots to fake their browser and device platform in order to mimic their victims or real users easily. The new implementation, of course, won’t be bypass-proof but will require the fraudsters and bot-developers to work harder in order to hide themselves and impersonate others.

As mentioned above, it is important to mention that this feature is currently considered experimental and its implementation may be changed in the next versions of Chrome.

Lastly, I wrote a very basic web application that implements these changes, you can find it here: https://ua-phaseout.herokuapp.com/ (Don’t forget to enable the Chrome flags beforehand!).