Edit a – Nick Coad Jul 15 '15 at 00:52

  • @gnack, you may be right but the offense would be mild and I would be more than happy to have them approach me about it and explain to me why I must have this script on my page, a year after we signed up with them when no such script injections took place. I know they have a ToS - good for them! – Andre Bulatov Jul 15 '15 at 00:54
  • @charlietfl, wow so until the browser parsed the line, the browser is not aware of its existence? Is there a JavaScript method to overtake the bworser parsing, scour through the non-DOM-loaded HTML file, chop up the script tags, and then turn parsing back over to the browser? At this point, all practicality aside, I just want to accomplish this :) – Andre Bulatov Jul 15 '15 at 00:56
  • @AndreBulatov is this the Analytics feature you're talking about? The wording in their ToS makes it sound like this is a feature that can be disabled - maybe look into that as an alternative option? – Nick Coad Jul 15 '15 at 00:57
  • 3
    @AndreBulatov the answers posted below are really your only option, if there's no legitimate way to disable them. – Nick Coad Jul 15 '15 at 00:58
  • @gnack, appreciated. I'll look into their backend again but I'm skeptical of the ability to disable it. Moreover, its not even a feature we can make use of as that's only for "Enterprise" level plans. And yet, the script is already running and collecting data. They *prolly* don't allow anyone to disable it as it'd lessen their "Enterprise" offering with a history of user behavior stats. – Andre Bulatov Jul 15 '15 at 01:04
  • 1
    If it's PHP, can you inject PHP code? If you can use PHP output buffering, you could strip the tags out before they are sent to the client. – Alexander O'Mara Jul 15 '15 at 01:11
  • 1
    You have to stay on a host doing script injection for *months*!? That sounds awful – chiliNUT Jul 15 '15 at 01:15
  • 1
    @Alexander O'Mara, hahaha I wish! PHP writing not allowed. What a blessing such a power would be. Like chiiNUT said, its awful out here for an aspiring dev. Or awesome, depending on how you look at it. Look what kind of lessons these people put me through! – Andre Bulatov Jul 15 '15 at 01:23
  • 1
    If you need some of the scripts they run for crucial functionality, it really sounds like a difficult task to isolate the good from the bad – charlietfl Jul 15 '15 at 01:27
  • 5 Answers5

    5

    Assuming the offending code is similar to that of the question you linked to, I would simply try to break the offending code so it fails to execute.
    From hereon the answer relies on code from the other question since you didn't provide any.

    The offending code relies on analytics, which is ensured on the page at the beginning of the script:

    (function(){
        window.analytics||(window.analytics=[]),window.analytics.methods=["debug","identify","track","trackLink","trackForm","trackClick","trackSubmit","page","pageview","ab","alias","ready","group","on","once","off","initialize"],window.analytics.factory=function(a){return function(){var b=Array.prototype.slice.call(arguments);return b.unshift(a),window.analytics.push(b),window.analytics}};for(var i=0;i<window.analytics.methods.length;i++){var method=window.analytics.methods[i];window.analytics[method]=window.analytics.factory(method)}window.analytics.load=function(){var a=document.createElement("script");a.type="text/javascript",a.async=!0,a.src="http://cdn2.bigcommerce.com/r6cb05f0157ab6c6a38c325c12cfb4eb064cc3d6f/app/assets/js/analytics.min.js";var b=document.getElementsByTagName("script")[0];b.parentNode.insertBefore(a,b)},window.analytics.SNIPPET_VERSION="2.0.8",window.analytics.load();
        //The rest of the script
    })();
    

    To break the whole script and prevent it from running you should simply assign window.analytics a value that will conflict with the methods that are used.
    So, for example, you could run a script before the offending script that simply assigns the following:

    window.analytics = function () {};
    

    Which will result in the offending script failing due to a type error.

    Etheryte
    • 24,589
    • 11
    • 71
    • 116
    • I appreciate this but though this seems like a possible solution, the problem is, I need to stop the actual JS files from loading. They cause major hang ups in rendering. – Andre Bulatov Jul 15 '15 at 01:00
    • @AndreBulatov Which is causing a hang, the loading time or the execution of the scripts? – Etheryte Jul 15 '15 at 01:01
    • Yeah, looks like some times its execution, sometimes the loading. However, I tried your solution and works well most times! Thing is, this line `b.parentNode.insertBefore(a, b)`, withing window.bcanalytics.load still loads. Even though your code initially breaks window.bcanalytics.push, somehow window.bcanalytics is restored for load? – Andre Bulatov Jul 15 '15 at 23:09
    • Updated in detail in Edit 2. – Andre Bulatov Jul 15 '15 at 23:19
    3

    If you know you can at least get your scripts to run first, one (albeit hacky) solution is to just absolutely "trash" the JS environment for the next script, so it has some problems. For example:

    //trash it
    document.getElementById=null;
    document.querySelector=null;
    document.querySelectorAll=null;
    window.console=null;
    window.alert=null;
    document.getElementsByTagName=null;
    document.getElementsByClassName=null;
    

    As soon as the enemy script tries using one of those functions, it will just crap out. Those are just some common methods off the top of my head... find out which ones its using, and nuke those. Of course, nuking anything you need for events on your own page could be an issue.

    chiliNUT
    • 18,989
    • 14
    • 66
    • 106
    • This is a great concept except the problem is, I need to stop the actual JS files from loading. They cause major hang ups in rendering. – Andre Bulatov Jul 15 '15 at 00:59
    • 1
      if you make them break, that is just as good. as soon as one of the scripts tries to use any of the above functions, it will immediately halt and return control back to your page – chiliNUT Jul 15 '15 at 00:59
    • 1
      the "hang ups" should go away just the same whether the script is crashed or not loaded – chiliNUT Jul 15 '15 at 01:00
    • Thank you sir, I will attempt this shortly and report back. – Andre Bulatov Jul 15 '15 at 01:01
    • 2
      @chiliNUT That said, the delay he means might be related to the time it takes for the script to be downloaded and loaded, which will still be there even if the script is broken. It's not a bad solution, but it's still not "just as good". – Peter Olson Jul 15 '15 at 01:02
    • 1
      gotta love the term ....`trash the js environment`! +1 for good laugh on that one – charlietfl Jul 15 '15 at 01:03
    • @chiliNUT he's talking about the time it takes to fetch the JS itself. – Nick Coad Jul 15 '15 at 01:03
    • Also, I would recommend saving the values so that you can untrash the js environment afterwards. – Peter Olson Jul 15 '15 at 01:03
    • @PeterOlson "just as good" was under the assumption that the delay was caused by the script being laggy and doing a lot of junk that makes the page hang; unless the script is some ungodly filesize I just wouldn't think the size alone would be a factor; but if it is, then yes, agreed, crashing it will not help that – chiliNUT Jul 15 '15 at 01:04
    3

    How are the scripts being injected? If it's through something like document.createElement, you could attempt to hijack that function and disable it if the element name is script:

    var origCreate = document.createElement;
    document.createElement = function (name) {
      if (name.toLowerCase() !== 'script') {
        origCreate.call(document, name);
      }
    };
    
    Jacob
    • 77,566
    • 24
    • 149
    • 228
    3

    Since the scripts are being inserted server-side, you won't be able to disable the running of the scripts in your JavaScript. However, if you're able to inject any arbitrary text before and after the scripts being inserted, you could try commenting out the script tags by inserting this first:

      <!--
    

    ...then this after:

      -->
    

    If the scripts get injected between these, it will hopefully cause the HTML parser to ignore the scripts.

    Update:

    Sounds like you need to disable just some of this content, so commenting everything out won't work. However, if before/after hijacking works, you could potentially wrap the injected scripts in a DOM element, parse that content, strip out the scripts you don't want, and inject the scripts so they run:

    Inject something like this before:

    <style id="hijack" type="text/html">
    

    ...and this after:

    </style>
    <script>
      var hijackedWrapper = document.getElementById('hijack');
      var scripts = hijackedWrapper.textContent;
      scripts = scripts.replace('<script src="http://some.domain.com/foo.js"></s' + 'cript>', '');
      document.write(scripts); // There's better ways to do this, but is just an illustration
    </script>
    
    Jacob
    • 77,566
    • 24
    • 149
    • 228
    • I'm not sure I see how this can be done. Say you have a script that loads before the hostile scripts, and add a ``? Keep in mind that the hostile scripts don't yet exist in the DOM yet. – Peter Olson Jul 15 '15 at 01:15
    • This is assuming you have hooks for before _and_ after whatever stage the tags are getting injected during. – Jacob Jul 15 '15 at 01:16
    • At least that's how I interpreted the comment `I can insert the script into the before their script tags or after.` – Jacob Jul 15 '15 at 01:17
    • I will look into this again but I don't think it'll work. Fact is, I can insert the after the line, and it will probably work well - too well! The issue here is simple -- their script generating line also generates other very necessary ecommercy resources, such as shopping cart and check-out scripts. It would disable the analytics, but also break some crucial functionality. – Andre Bulatov Jul 15 '15 at 01:18
    • If you wanted to get _really_ hacky, you could insert the before/after text to make them not scripts, parse the DOM, strip out the offending parts, then re-insert into the page. :/ – Jacob Jul 15 '15 at 01:21
    • Can you insert a snippet that has a proof-of-concept? I'm curious to see how you dynamically insert HTML comments into a page. – Peter Olson Jul 15 '15 at 01:22
    • 1
      Your original answer may not have answered the question for OP's specific case, but I think it was still a positive contribution to the discussion, and would be useful for other victims of script injection. I like this one too though – chiliNUT Jul 15 '15 at 01:25
    • Added a sample. I have _no idea_ if this will work. Testing. – Jacob Jul 15 '15 at 01:31
    • Tried this awesome solution, but failed hard. My fault though. Solution is great, but alas, I was wrong about how they are injected. Basically, BC engineers are just as sneaky as we are and are PREpending their script tags to the first non-commented out ` – Andre Bulatov Jul 15 '15 at 23:27
    1

    Like the others, I would suggest sabotaging the js environment for the hostile script, and then recovering it back once you need it.

    For example, if the script relies on document.getElementById, you can do this

    var restore = {
      getElementById: document.getElementById
    };
    document.getElementById = null;
    

    and then if you have a need to use document.getElementById later, you can restore it back:

    document.getElementById = restore.getElementById;
    

    I also wanted to note that removing the actual script tags, as far as I can tell, is not possible:

    • If you put in a script before the hostile scripts, then they will not be loaded in the DOM yet, so it can't see anything to remove.
    • If you put in a script after the hostile scripts, the hostile scripts will already be loaded.
    Peter Olson
    • 139,199
    • 49
    • 202
    • 242
    • Love it! Def gonna try. I just hope I am able to isolate the one or two scripts I need to destroy. The issue is, before I can restore the methods, several other necessary scripts will also load. So, I have control, then ~6 scripts load -- 2 of which I need to block -- then I get control back. Thanks. – Andre Bulatov Jul 15 '15 at 01:27