3

I'm writing a Javascript code that needs to watch for new 'script' elements, and to block a few known sources.

To catch those, I've tried using MutationObserver and __ defineSetter __ , both can watch for the 'src' change, but only after the HTTP request is already being sent - so even if I change the src, it's not really being blocked.

window.HTMLScriptElement.prototype.__defineSetter__('src', function (d) 
    {
        console.log("HTMLScriptElement: ",d);
        if (d.indexOf('localhost') != -1) {
            //BLOCK SCRIPT
        }
    });

    new MutationObserver(function (a) {
        a.forEach((e) => {
            e.addedNodes.forEach((z) => 
            {
                if (z.nodeName.toLowerCase() == "script" && z.src.indexOf('localhost') != -1) 
                {
                    //BLOCK SCRIPT
                }
            })
        })
    }).observe(window.document, {
        attributes: true,
        childList:true,
        subtree:true
    });
  • MutationObserver alone is enough but you need to 1) remove the element, not just change its src, then create a new element if you want, and 2) check nested nodes as well because addedNodes is not flattened so some site may add a container element with scripts inside. – wOxxOm Sep 02 '20 at 13:25

1 Answers1

1

You could use Service workers in order to intercept network requests. Something like this should do the trick:

self.addEventListener('fetch', function (event) {
    const blockedUrls = [
        //...
    ];
    if (blockedUrls.some(x => event.request.url.startsWith(x))) {
        event.respondWith(new Response('blocked', { status: 401, statusText: 'Unauthorized' }));
    }
});
Guerric P
  • 30,447
  • 6
  • 48
  • 86
  • You have to write this in a separated file (dedicated to the service worker) and register it with `navigator.serviceWorker.register('./sw-test/sw.js')`. For more information: https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API/Using_Service_Workers#Enter_service_workers – Guerric P Sep 02 '20 at 12:13
  • I'm not able to use Service workers, since my code runs on some sites other than mine. If I understand correctly, I need to install it - so I'm not able to use it – Liron Avital Sep 02 '20 at 12:14
  • Then indeed it won't work since the origin of the service worker script has to be the same as the current origin – Guerric P Sep 02 '20 at 12:27
  • Thanks anyways, any other ideas? – Liron Avital Sep 02 '20 at 12:48
  • Unfortunately I have no other ideas, I actually doubt this is possible. – Guerric P Sep 02 '20 at 13:54
  • I don't know if you found a solution yet, but you should try a similiar approach to the `HTMLScriptElement.prototype.__defineSetter__('src', function (d)` but with a [Proxy](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy). Replace the native `HTMLScriptElement` with your own `Proxy` (built from the native `HTMLScriptElement`). I have answered a question with a similar solution here: https://stackoverflow.com/questions/57523910/intercept-html5-web-notifications-in-a-browser-environment/57572671#57572671 – Guerric P Sep 08 '20 at 13:02