Is there a plan to handle sec-ch-ua headers in Phoenix?

My Chrome dev tools is warning me about changes to the user-agent string being provided by the browser. It appears to me that, sooner or later, this is going to affect Phoenix in some way, since it makes some use of the user-agent string, and affect me since my app uses the userAgent parameter that Phoenix passes in join requests. Is there a plan for Phoenix to make changes to conditionally use the sec-ch-ua* strings when they are available in headers, or request them once the user-agent is “reduced”?

1 Like

I do not understand what you mean by “handle”. This header will be available like any other header in Plug.Conn and it is up to user to make sense out of these headers.

1 Like

A Phoenix endpoint configuration does explicitly support passing :user_agent to the :connect_info option which will copy the User-Agent header from the transport to the user socket connect/3 callback.

Perhaps in the future some additional :connect_info options or other adjustments may be relevant.

1 Like

This bit is a little cryptic and would be more clear if you add to your post a relevant link to explain it. For example:

1 Like

Here’s the link provided in the devtools console:

Here’s the doc in transport.ex about what can be requested:

@doc """
  Extracts connection information from `conn` and returns a map.

  Keys are retrieved from the optional transport option `:connect_info`.
  This functionality is transport specific. Please refer to your transports'
  documentation for more information.

  The supported keys are:

    * `:peer_data` - the result of `Plug.Conn.get_peer_data/1`
    * `:trace_context_headers` - a list of all trace context headers
    * `:x_headers` - a list of all request headers that have an "x-" prefix
    * `:uri` - a `%URI{}` derived from the conn
    * `:user_agent` - the value of the "user-agent" request header
  def connect_info(conn, endpoint, keys) do

Here’s the code in transport.ex that reads the header:

  defp fetch_user_agent(conn) do
    with {_, value} <- List.keyfind(conn.req_headers, "user-agent", 0) do

So, I guess the question is: Given that the user-agent header is being “reduced” per Google’s wording (and other more pejorative descriptions per other sources), should the Phoenix transport option to pass user-agent information be changed to provide, for instance, the sec-ch-ua, sec-ch-ua-mobile and sec-ch-ua-platform headers? If so should it be done in a consolidated form that effectively hides the change from users of the option, or should the single header be replaced with 3 individual components, with 1 or 3 options?

1 Like

Given that one of the specific benefits cited in the Sec-CH-UA-* work is to reduce the effort of parsing specific values out of User-Agent, this doesn’t seem like a good path to take.

I’m curious what folks are actually using user_agent for, though - it’s been a Bad Idea to try to get information out of that field for a looooooooong time. I’ve only ever seen it in analytics / logs where it’s treated like an opaque value.

1 Like

We are using it to extract whether the client is mobile or not, (iOS or Android, and Chrome or not. The new headers if used directly seem to make that easier, but my question is whether the Phoenix code should simplify life for users of the user-agent downstream (by hiding the change), or create three separate options to control the three separate “low-entropy” headers, or just one option, but providing three parts to the response. I’m pretty flexible given that I see this thing coming, I’m just wondering if we want to protect the unknowing users of user-agent that don’t see this coming. But I definitely feel that Phoenix needs to do something with the new headers, thus this post.

I work as a Developer Advocate for Mobile API Security and I am a strong believer that all layers of security are important to increase the effort necessary to get into your perimeter. The thing that we kept seeing people saying that its security by obfuscation or whatever was a brain wash from security vendors that got into the mindset of a lot of devs and management.

With that said, I want to alert you that relying solely on the user-agent for segmenting mobile clients and web clients is not enough, because its very easy to bypass, thus I recommend you to have additional measures in place to safeguard against it.

1 Like

The docs for the user-hints say that they aren’t currently supported in anything but Chrome, and the Firefox discussion around the reduced User-Agent string suggests that the FF team is not inclined to implement them either (but is implementing the reduced UA value).

Taken together, it seems like the only reliable cross-platform value will be the new, reduced User-Agent string.

One other note: in at least Mobile Safari (the only mobile browser I have at hand), using the “Request Desktop Website” button sends a fake User-Agent for an Intel Mac.

1 Like

The places that we use the user-agent are, I believe, all post-authentication, so are from users who have already passed security checks and we just need to know whether to send them desktop notifications of things, or APNS or FCM Push notifications. The authentication is all generic, or may differentiate based on whether you send me an Apple token or not, but isn’t based on the UA.

I don’t want to derail this topic, thus I will just say that security checks need to also occur for authenticated users, otherwise an attacker that grabs an auth token can easily manipulate your API to exfiltrate data he shouldn’t have access to, like notifications or whatever. If you want to learn more you can read some of my replies with the security tag on Stackoveflow.

For some examples of why we need to eventually align with the new specification there are some highlighted use cases: User-Agent Client Hints

This link also simplifies what information will be available in the API Improving user privacy and developer experience with User-Agent Client Hints

I don’t have a strong personal position in the whole “are client hints good or not” debate, but there’s been considerable discussion about it at Mozilla:

TBH I find the arguments about “working around browser bugs” unpersuasive, given that the only browser that currently sends the headers is newish versions of Chrome :man_shrugging: