Search code examples
javascriptgoogle-chromegoogle-chrome-extensionnavigatorfido-u2f

How can I replace navigator.credentials.create request or response parameters through a Chrome extension?


I am working on a chrome extension to modify U2F create request parameters from a web service. Is it possible to replace navigator.credentials.create request or response parameters through a Chrome extension? I couldn't find resources related to this. Any pointers would be helpful.

In particular, when a user registers a U2F for a website, it calls browsers web API navigator.credentials.create which in turn contacts the hardware token and returns the response. I want to modify the request and response from the navigator.credentials.create API, called by the webpage.


Solution

  • There is no way of achieving what you want through Chrome APIs. Chrome does not offer any kind of API to modify requests or other kind of data "on the fly" like you'd want to do. I can only assume that this is most likely a security measure.

    However, since you say that you want to modify the data that is passed and returned by navigaror.credentials.create() on some particular website, you can easily do this with a content script that replaces the function with a custom handler and acts as a proxy, intercepting all calls and potentially modifying data.

    Whether this makes any sense or not depends on what specifically you want to do when intercepting these calls. It's important to mention that as @gcochard makes us notice in a comment:

    The whole point of U2F/WebAuthN is to make a cryptographically secure challenge/response scheme for strong authentication over the web. Inserting a proxy and changing the request and response will break that cryptographic challenge/response in any context where you're not a MITM, leaving your users dependent upon your extension to authenticate. It might help to explain what you're trying to do with this data.

    Either way, you could still log and access the data, so there could be meaningful applications of this strategy.

    I will only outline what the content script should do, if you also don't know how to inject a content script in a page, refer to this documentation page. In any case, you want your script to run as soon as possible, so make sure to have "run_at": "document_start".

    The content script will do the following:

    1. Create a <script> tag inside the page, loading some code inside it, which will:
    2. Save the create() method of navigator.credentials it in another variable.
    3. Replace the original create() method with a function that "filters" the calls made to it and internally calls the real method.

    So here's a simple content script that achieves your goal:

    const code = `
        const real_create = navigator.credentials.create.bind(navigator.credentials);
    
        navigator.credentials.create = function() {
            // Modify the arguments how you want.
            console.log(arguments);
    
            // Call the real method with the modified arguments.
            let res = real_create.apply(arguments);
    
            // Modify the return value how you want, then return it.
            console.log(res);
            return res;
        }
    `;
    
    const script = document.createElement('script');
    script.textContent = code;
    (document.documentHead || document.documentElement).appendChild(script);
    script.remove();
    

    The above should do exactly what you want, it's only a matter of injecting it into the right page.

    NOTE: the code variable is created using a template string literal, delimited by the characters `, if you don't want to use template literals you can use an array of strings and then join it. You can also refer to this answer which lists other ways to inject code into a page from a content script.