Fraud detection: how to detect if a user lied about its OS and infer its real OS?

In the context of fraud detection, you may want to detect the user's OS, e.g. to know whether or not the user pays with its credit card from a known device. The usual way to obtain the user OS is to parse the user agent or the client hints HTTP header. However, when it comes to fraud detection, you can't always assume the user agent has been left untouched. Fraudsters use different kinds of anti-detect browsers and browser extensions that may lie about the user agent, including the OS.
In this article, we present different techniques that can be used to detect whether or not a user lied about its OS and user agent, and try to infer the real OS even when the user agent has been modified.
Before we go through the advanced techniques to infer the real user OS, let’s see how we can extract the OS from HTTP headers, in the case where the user didn’t forge them:

The simple way: detecting the OS using the user-agent and sec-ch-ua-platform HTTP headers

The user agent is an HTTP header that provides information about the user’s browser, OS, and version. For example, a user using Chrome 125 on MacOS may have the following user-agent Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36 while a user on Mobile Safari on IOS may have the following user agent Mozilla/5.0 (iPhone; CPU iPhone OS 17_2_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.2 Mobile/15E148 Safari/604.1

In these user agents, we can identify the type of browser, the OS, and their versions. However, user agents are not standardized and may be challenging to parse. I recommend you use existing libraries such as UAParser.js and Python user agents to parse them.

Another more recent HTTP header that can be used to infer the user OS is sec-ch-ua-platform. It may have some of the following values:

  • "macOS"
  • "Android"
  • "Linux"
  • "Windows"

If you want a more exhaustive and up-to-date list of possible values for the sec-ch-ua-platform, you can look at this page, which is frequently updated. Note that as of June 2024, only Chromium-based browsers send this HTTP header.

Inferring the OS the hard way: using JavaScript APIs

In the context of fraud detection, you may want to verify the nature of the OS claimed in the user-agent by leveraging other signals collected using JavaScript.

navigator.userAgentData.platform provides information about the device platform, e.g. macOS . You can combine it with userAgentData.getHighEntropyValues(...).platformVersion to obtain more information about the platform version.

Similarly, you can leverage navigator.platform. The value is slightly different than the one returned by navigator.userAgentData.platform , but it should be consistent/correlated with it. You can find a list of the possible values of the navigator.platform attribute on this page.

Inferring the OS through observable side effects

While the previous APIs explicitly returned information about the OS, keep in mind that they may also be overridden by malicious actors. Thus, you may want to verify the OS claimed by these APIs by leveraging other APIs whose values are correlated with the OS. For example, we can use attributes related to the screen resolution, such as screen.width/height and screen.availWidth/height . Certain screen resolutions are incompatible with certain OS, e.g. an iPhone with a screen resolution as big as a connected TV. Depending on the OS, you may be able to detect the presence of the toolbar and certain native UI elements specific to this OS or to a family of devices like an iPhone.

GPU-related attributes: APIs related to the GPU often leak information about the underlying OS and can be used to verify the authenticity of the OS claimed in the user agent. Indeed, certain GPU models are only available on certain types of devices. Moreover, some of these APIs leak information about the OS. You can obtain information about the device GPU using the WebGL and the WebGPU APIs.

  • With WebGL, you can collect information about the GPU vendor and renderer using UNMASKED_VENDOR_WEBGLand UNMASKED_RENDERER_WEBGL. On a Mac M2 with Chrome, you may have the following GPU vendor Google Inc. (Apple)and the following GPU renderer ANGLE (Apple, ANGLE Metal Renderer: Apple M2 Pro, Unspecified Version)which indicates the user is on a Mac M2.
  • With the WebGPU API GPUAdapterInfo.requestAdapterInfo(), you can also obtain information about the user GPU model. On Mac OS it may look as follows {"vendor":"apple","architecture":"common-3","device":"","description":""}. On Android, you may see a GPU linked to Qualcomm with an Adreno architecture:
{
      "vendor": "qualcomm",
      "architecture": "adreno-6xx",
      "device": "",
      "description": ""
    }

Canvas fingerprinting challenges, in particular those that include emojis can be used to infer the user OS. Indeed, graphics rendering, and specifically emojis rendering depends on the OS. The three canvas challenges below come from different devices on different OSes. We observe significant differences in the rendering of the emojis. Thus, you can build a database that maps certain canvas values to a given OS.

Font enumeration: Finally, you can also leverage font enumeration to infer the presence and absence of fonts. By testing key fonts that are linked to specific OS, you may be able to infer the true user OS. By default, the browser fingerprinting test of device and browser info verifies the presence of the following fonts:

[
                'sans-serif-thin',
                'ARNO PRO',
                'Agency FB',
                'Arabic Typesetting',
                'Arial Unicode MS',
                'AvantGarde Bk BT',
                'BankGothic Md BT',
                'Batang',
                'Bitstream Vera Sans Mono',
                'Calibri',
                'Century',
                'Century Gothic',
                'Clarendon',
                'EUROSTILE',
                'Franklin Gothic',
                'Futura Bk BT',
                'Futura Md BT',
                'GOTHAM',
                'Gill Sans',
                'HELV',
                'Haettenschweiler',
                'Helvetica Neue',
                'Humanst521 BT',
                'Leelawadee',
                'Letter Gothic',
                'Levenim MT',
                'Lucida Bright',
                'Lucida Sans',
                'Menlo',
                'MS Mincho',
                'MS Outlook',
                'MS Reference Specialty',
                'MS UI Gothic',
                'MT Extra',
                'MYRIAD PRO',
                'Marlett',
                'Meiryo UI',
                'Microsoft Uighur',
                'Minion Pro',
                'Monotype Corsiva',
                'PMingLiU',
                'Pristina',
                'SCRIPTINA',
                'Segoe UI Light',
                'Serifa',
                'SimHei',
                'Small Fonts',
                'Staccato222 BT',
                'TRAJAN PRO',
                'Univers CE 55 Medium',
                'Vrinda',
                'ZWAdobeF',
            ];

Conclusion

Verifying the nature of a user OS is key in the context of fraud detection. It can be used to verify if a user is doing a critical action from a known device. However, fraudsters know it and may be tempted to lie about their real OS to imitate the fingerprint of their victim.

In this article, we showed that by verifying the consistency of the OS claimed in the user agent with the different signals presented in this article, such as navigator.platform , UNMASKED_RENDERER_WEBGL , and the rendering of emojis in a canvas fingerprint, you can detect inconsistencies that indicate that the user altered the OS claimed in its user agent.

Disclaimer: you should keep in mind that all the APIs and attributes presented in this article can also be overridden by an attacker. Thus, it’s important to leverage as many signals as possible to verify their consistency between each other.