3

I am working on a chrome extension in which I am replacing the chrome's web API function navigator.credentials.create with a custom handler. navigator.credentials.create is called when a user initiates a 2FA registration for a security key.

The custom handler is working on facebook.com but, it doesn't work on mail.google.com.

I have attached the minimal code for the extension I'm working on. This script is injected on every page and can be confirmed through console "injected script". In my sample app, I printed a console statement "In extension's create" in the custom handler of navigator.credentials.create. This should be printed whenever a user initiates the 2FA registration process. It is working for facebook but doesn't work on https://myaccount.google.com/. I have verified that the script is inserted in all iframes available on the website. I also confirmed that mail.google.com is not using service workers to call navigator.credentials.create API.

content_script.js

const webauthnInject = document.createElement('script');
webauthnInject.type = 'text/javascript';
webauthnInject.src = 'chrome-extension://' + chrome.runtime.id + '/inject_webauthn.js';
document.documentElement.appendChild(webauthnInject);

inject_webauthn.js

(() => {

    console.log("injected script");

    const real_create = navigator.credentials.create;
    navigator.credentials.create = async function() {
        console.log("In extension's create");
        let res = await real_create.bind(navigator.credentials)(arguments[0]);
        return res;
    };

})();

manifest.json

{
  "manifest_version": 2,
  "name": "sample app",
  "description": "A Sample app",
  "version": "1.0.2",
  "minimum_chrome_version": "36.0.1985.18",
  "content_scripts": [
    {
      "all_frames": true,
      "match_about_blank": true,
      "matches": [
        "https://*/*",
        "http://*/*"
      ],
      "exclude_matches": [
        "https://*/*.xml"
      ],
      "run_at": "document_start",
      "js": [
        "content_script.js"
      ]
    }
  ],
  "background": {
    "persistent": false,
    "scripts": [
      "background.js"
    ]
  },
  "content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'",

  "permissions": [
    "tabs",
    "storage",
    "https://*/*",
    "http://*/*"
  ],
  "web_accessible_resources": [
    "inject_webauthn.js"
  ]
}
Hamza Rashid
  • 1,329
  • 15
  • 22
Mukesh Gupta
  • 1,373
  • 3
  • 17
  • 42
  • Last time we discussed this, the guess was that the site is using an empty iframe to extract the native API. To prevent that you'll need to override document.createElement in [page context](/a/9517879) and somehow spoof it. – wOxxOm Jun 19 '20 at 04:02
  • @wOxxOm Shouldn't `"all_frames": true` and `"match_about_blank": true` insert the content_script even in empty frames? Do I override document.createElement and insert script when new iframe is created? It's a bit unclear. Can you please elaborate if `match_about_blank` is not the right way to do it? – Mukesh Gupta Jun 20 '20 at 02:42
  • Chrome won't inject in iframes that don't require network loader i.e. those with an empty `src` or `srcdoc` or `src="javascript:..."` and so on. Overriding createElement should be performed in the document that creates such an iframe. I don't know which one does. – wOxxOm Jun 20 '20 at 03:20

0 Answers0