6

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.

Community
  • 1
  • 1
Andrew Ensley
  • 11,611
  • 16
  • 61
  • 73

4 Answers4

3

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.

Andreas Köberle
  • 106,652
  • 57
  • 273
  • 297
1

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);
Community
  • 1
  • 1
Andrew Ensley
  • 11,611
  • 16
  • 61
  • 73
  • 1
    Please note that – Lee Davis Aug 05 '15 at 09:34
0

You could listen for changes in DOM and see if a new script tag is being inserted. But may I ask, what is the reason for such a need? I doubt you will be able to detect all possible cases where some arbitrary JS is executed against your page's DOM (e.g. a bookmarklet, or greasemonkey script).

fest
  • 1,545
  • 12
  • 17
  • 2
    For the reason: 1. Just to see if I can :-) 2. Would be useful in debugging javascript/ui issues reported by users if I knew there was other stuff going on. Edit: Also, I'm not really concerned with bookmarklets or even greasemonkey scripts really. The user knows they're clicking the bookmarklet, and greasemonkey users are likely to understand what's causing an issue if something goes crazy. The main thing I'm trying to accommodate are the clueless users who have "$$ Ultimate Coupons $$" addons that load external scripts. – Andrew Ensley Apr 18 '12 at 21:22
0

I think the same origin policy may cover this: http://en.wikipedia.org/wiki/Same_origin_policy

matpol
  • 3,042
  • 1
  • 15
  • 18
  • 3
    This only applies to AJAX requests. I'm talking about script elements on the page with external sources, which are the basis for JSONP. – Andrew Ensley Apr 18 '12 at 21:30
  • you could check for events being bound to elements: http://stackoverflow.com/questions/1515069/jquery-check-if-event-exists-on-element – matpol Apr 18 '12 at 21:41