Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Javascript: Detect/Prevent External Scripts

Is it possible to detect external scripts that might be loaded into a page by browser add-ons, a proxy, xss, etc?

Say I have this web page:

<html>
    <head>
        <title>Hello world!</title>
        <script src="http://mydomain.com/script.js"></script>
    </head>
    <body>
        Hello world!
    </body>
</html>

Would it be possible to include some script in my script.js file that would detect when other script elements on the page do not originate from http://mydomain.com?

I want something that could detect other scripts somehow included in the source (i.e. they are present when the onload event fires) and scripts added any time after page load.

If I can detect those scripts, can I also stop them somehow?

This would be useful in debugging javascript/ui issues reported by users if I knew there was other stuff going on.

I use jQuery, so a jQuery answer will work for me. I just didn't want to limit answers to jQuery only.


EDIT

My solution is below. However, there are two (potential) problems with it:

  1. It depends on jQuery.
  2. It will not detect foreign resources loaded via CSS @import rules (or any rule with a url() value).

If someone would like to submit an answer that solves one or both of those issues, I will upvote it.

If you solve both, I will accept your answer.

like image 500
Andrew Ensley Avatar asked Apr 18 '12 21:04

Andrew Ensley


People also ask

How do I block third party scripts?

If you are using Google Tag Manager to include scripts on your website, you should use Google Tag Manager to block third-party scripts. Automatic script blocking will not work with Google Tag Manager since Google Tag Manager itself is a system to manage scripts without editing website code.

How do I stop script execution?

Changing the script type attribute Changing the type attribute to something other than application/javascript before the script payload is retrieved actually allows us to completely stop the script from executing. This does the magic in Chrome , Safari , IE and Edge .


2 Answers

You could check all script elements on domready like this:

$(function () {
    $('script').each(function () {
        check script source here
    })
})

but, if someone could inject script tags in your side, he can also delete your code before you can start the check, also it will be hard to delete objects and functions the script could create before your recognize it.

So I dont think its a good solution to start investing time in this field. Its much more important to be clear that you cant trust the client anyway.

As you wanna figure out it anyway there are a bunch of DOM events to check if the DOM tree has changed.

like image 147
Andreas Köberle Avatar answered Sep 28 '22 07:09

Andreas Köberle


I wasn't satisfied with the answers I received (though I appreciate Andreas Köberle's advice), so I decided to tackle this myself.

I wrote a function that could be run on demand and identify any html elements with foreign sources. This way, I can run this whenever reporting a javascript error to get more information about the environment.

Code

Depends on jQuery (sorry, element selection was just so much easier) and parseUri() (copied at the bottom of this answer)

/**
 * Identifies elements with `src` or `href` attributes with a URI pointing to
 * a hostname other than the given hostname. Defaults to the current hostname.
 * Excludes <a> links.
 * 
 * @param string myHostname The hostname of allowed resources.
 * @return array An array of `ELEMENT: src` strings for external resources.
 */
function getExternalSources(myHostname)
{
    var s, r = new Array();
    if(typeof myHostname == 'undefined')
    {
        myHostname = location.hostname;
    }
    $('[src], [href]:not(a)').each(function(){
        s = (typeof this.src == 'undefined' ? this.href : this.src);
        if(parseUri(s).hostname.search(myHostname) == -1)
        {
            r.push(this.tagName.toUpperCase() + ': ' + s);
        }
    });
    return r;
}

Usage

var s = getExternalSources('mydomain.com');
for(var i = 0; i < s.length; i++)
{
    console.log(s[i]);
}

// Can also do the following, defaults to hostname of the window:
var s = getExternalSources();

The search is inclusive of subdomains, so elements with sources of www.mydomain.com or img.mydomain.com would be allowed in the above example.

Note that this will not pick up on foreign sources in CSS @import rules (or any CSS rule with a url() for that matter). If anyone would like to contribute code that can do that, I will upvote and accept your answer.


Below is the code for parseUri(), which I obtained from https://gist.github.com/1847816 (and slightly modified).

(function(w, d){
    var a,
        k = 'protocol hostname host pathname port search hash href'.split(' ');
    w.parseUri = function(url){
        a || (a = d.createElement('a'));
        a.href = url;
        for (var r = {}, i = 0; i<8; i++)
        {
            r[k[i]] = a[k[i]];
        }
        r.toString = function(){return a.href;};
        r.requestUri = r.pathname + r.search;
        return r;
    };
})(window, document);
like image 30
Andrew Ensley Avatar answered Sep 28 '22 07:09

Andrew Ensley