95

I understand that making user-agent hints more ambiguous is intended, in part, to make browser fingerprinting harder.

My own (Windows desktop) Chrome sends the headers:

user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.75 Safari/537.36
sec-ch-ua: "Chromium";v="86", "\"Not\\A;Brand";v="99", "Google Chrome";v="86"
sec-ch-ua-mobile: ?0

What I don't get is:

  1. Why the string "Not A Brand" specifically? Does anyone else use this pseudo-UA? Is this a joke of some sort?
  2. Why the \" and \\A; inside the string? My only guess is that this is supposed to mess with parsers somehow (like the anti-IE hacks in CSS), but that seems like a rather odd purpose — and IIRC, \A is the bell character.
  3. How is this supposed to accomplish user-agent hint ambiguity, given that it also sends the full user-agent header, which has the specific version numbers?
  4. While at it: why does Chrome's user-agent also claim to be Mozilla, AppleWebKit, and Safari? It isn't, and this user-agent string is distinctively Chrome's. Does it have some sort of embedded components from those other browsers?
sideshowbarker
  • 81,827
  • 26
  • 193
  • 197
Sai
  • 6,919
  • 6
  • 42
  • 54
  • 1
    To comment on point 2 of you question: I suspect that `\"` gets unescaped to `"` and `\\ ` to `\ `, so the bell character `\A` is never being parsed. – William Oct 20 '20 at 10:39
  • About point 3 see https://groups.google.com/a/chromium.org/g/blink-dev/c/-2JIRNMWJ7s/m/yHe4tQNLCgAJ it is in the plan to freeze and cleanup the user-agent – Arye Eidelman Jun 01 '21 at 15:56
  • About point 4 see https://web.dev/user-agent-client-hints/#background every new browser had to copy an existing user agent for compatibility reasons and then added new information about itself and its version etc. – Arye Eidelman Jun 01 '21 at 15:59
  • 1
    Further on question 4, [every browser pretends to be every other browser (or at least they all claim to be Mozilla)](https://webaim.org/blog/user-agent-string-history/). – TRiG Jul 19 '21 at 19:20

1 Answers1

80

It seems that it's part of Chromium's GREASEing strategy:

User agents' brands containing more than a single entry could encourage standardized processing of the UA string. By randomly including additional, intentionally incorrect, comma-separated entries with arbitrary ordering, they would reduce the chance that we ossify on a few required strings.


Looking at the Chromium repository, it seems that it was introduced in this commit

The commit description given is:

[client-hints] GREASEing the Sec-CH-UA list

Randomizing order and string with escaped characters to ensure proper
parsing and prevent ossification.

It also links to this ticket in the bug tracker.

William
  • 2,695
  • 1
  • 21
  • 33
  • 10
    Having *some* false entry, e.g. "Not A Brand", would fulfill the objectives you bolded. But that doesn't explain why they call it "Not A Brand" specifically — nor why the escaped characters. Well done finding that commit, but its message doesn't really explain those either (nor does the ticket). Hence the specific questions in my OP. – Sai Oct 20 '20 at 11:39
  • 11
    Going by the commit message I would say the escaped character are there just to ensure that whoever will eventually parse the UA will be forced to correctly implement all the "cases" that could happen in a UA string. – William Oct 21 '20 at 09:18
  • 25
    It's probably a bit off-topic but this feels a lot like what Golang sometimes does, to ensure that people don't rely on "not guaranteed" behaviors. For example: the iteration order on a map is _purposely unpredictable_ just to force programmers to not rely on a specific order. See https://github.com/golang/go/issues/6719 – William Oct 21 '20 at 09:23
  • 1
    Interesting point re using it as a case test. *That* makes sense as a thing one might do; I hadn't thought of what the permitted string content was such that one might want to fuzz it. That seems like a pretty good answer. – Sai Oct 22 '20 at 22:03