Is it possible to remove script tags in the of an HTML document client-side and prior to execution of those tags?
On the server-side I am able
Since you cannot prevent future tags from evaluating (whenever the
tag has been found, the corresponding code of
is fetched and evaluated.
will block a document from loading further till the source is fetched unless the
async
attribute is set), a different approach need to be taken.
Before I present the solution, I ask: What can prevent a script within a tag from executing? Indeed,
from the source code.1 is obvious, and 2 can be derived from the documentation, so I'll focus on 3. The examples below are obvious, and need to be adjusted for real-world use cases.
Here's a general pattern for proxying existing methods:
(function(Math) {
var original_method = Math.random;
Math.random = function() {
// use arguments.callee to read source code of caller function
if (/somepattern/.test(arguments.callee.caller)) {
Math.random = original_method; // Restore (run once)
throw 'Prevented execution!';
}
return random.apply(this, arguments); // Generic method proxy
};
})(Math);
// Demo:
function ok() { return Math.random(); }
function notok() { var somepattern; return Math.random(); }
In this example, the code-blocker runs only once. You can remove the restoration line, or add var counter=0;
and if(++counter > 1337)
to restore the method after 1337 calls.
arguments.callee.caller
is null
if the caller is not a function (eg. top-level code). Not a disaster, you can read from the arguments or the this
keyword, or any other environment variable to determine whether the execution must be stopped.
Demo: http://jsfiddle.net/qFnMX/
Here's a general pattern for breaking setters:
Object.defineProperty(window, 'undefinable', {set:function(){}});
/*fail*/ function undefinable() {} // or window.undefinable = function(){};
Demo: http://jsfiddle.net/qFnMX/2/
And getters, of course:
(function() {
var actualValue;
Object.defineProperty(window, 'unreadable', {
set: function(value) {
// Allow all setters for example
actualValue = value;
},
get: function() {
if (/somepattern/.test(arguments.callee.caller)) {
// Restore, by deleting the property, then assigning value:
delete window.unreadable;
window.unreadable = actualValue;
throw 'Prevented execution!';
}
return actualValue;
},
configurable: true // Allow re-definition of property descriptor
});
})();
function notok() {var somepattern = window.unreadable; }
// Now OK, because
function nowok() {var somepattern = window.unreadable; }
function ok() {return unreadable;}
Demo: http://jsfiddle.net/qFnMX/4/
And so on. Look in the source code of the scripts you want to block, and you should be able to create a script-specific (or even generic) script-breaking pattern.
The only downside of the error-triggering method is that the error is logged in the console. For normal users, this should not be a problem at all.