在加载和运行脚本之前编辑 <head> 中的 <script> 标记

Edit a <script> tag in the <head> before it loads and runs the script

我在一个电商平台,可以编辑<head>,但是有些注入头部的东西,用户是够不着的。所以即使我们可以编辑<head>,也有一些注射是无法达到的,因此无法通过传统方法去除。
PS:我可以将脚本放在这些注入的 JS 脚本标签之前或之后,这些标签与我的脚本一起生成和填充。因此,如果我将我的脚本放在它们的 "tag injection line."

之前,我的脚本将在注入的标签之前 运行

问题

问题是,这个平台开始向头部注入分析和垃圾邮件,基本上是劫持我们的客户信息并将其出售给第三方。所以我想禁用他们蹩脚的脚本。

<script type="text/javascript" async="" src="/some.JS.file.min.js"></script>
<script type="text/javascript" async="" src="/another.JS.file.min.js"></script>

问题

是否可以使用 javascript 或 jquery 编写一个脚本来在 运行 之前编辑标签? 我可以在注入标签之前插入这个自定义脚本。我错了——不需要的 <script> 标签总是预先添加到第一个未注释的 <script>标签,因此 javascript 无法在标签 运行.

之前破解标签

到目前为止我尝试了什么

我从 this SO question.

中找到了这个不完整且无效的答案

当我 运行 为我自己的站点输入包含正确详细信息的完整脚本时,我遇到很多错误 很难知道从哪里开始不知道所有的 XHR 东西是干什么用的,有些错误是我以前从未见过的。

当我运行只是这一部分时,我有点理解:

doc = document.implementation.createHTMLDocument(""+(document.title || ""));

scripts = doc.getElementsByTagName("script");
//Modify scripts as you please
[].forEach.call( scripts, function( script ) {
    if(script.getAttribute("src") == "/some.JS.file.min.js"
       || script.getAttribute("src") == "/another.JS.file.min.js") {

        script.removeAttribute("src");
    }
});

编辑更新:

他们的脚本插入在我的脚本之后。也就是说,我可以将脚本插入到 <head> 的脚本标签之前或之后。我们现在正在研究新的平台,但我仍然需要同时解决这个问题,因为在我们切换之前还需要几个月的时间。我希望 g 有一些 JavaScript 我不知道可以在它们 运行 之前编辑 HTML 脚本标签,如果这个脚本在它们之前 运行s。

编辑 2:

window.bcanalytics = function () {}; 效果很好,通过破坏 window.bcanalytics.push 破坏了大部分,但不知何故,其中一些仍然存在。

在此区块中:

    <script type="text/javascript">

(function() {
    window.bcanalytics || (window.bcanalytics = []), window.bcanalytics.methods = ["debug", "identify", "track", 
        "trackLink", "trackForm", "trackClick", "trackSubmit", "page", "pageview", "ab", "alias", "ready", "group", 
        "on", "once", "off", "initialize"], window.bcanalytics.factory = function(a) {
        return function() 
        {
            var b = Array.prototype.slice.call(arguments);
            return b.unshift(a), window.bcanalytics.push(b), 
            window.bcanalytics
        }
    };
    for (var i = 0; i < window.bcanalytics.methods.length; i++) 
    {
        var method = window.bcanalytics.methods[i];
        window.bcanalytics[method] = window.bcanalytics.factory(method)
    }
    window.bcanalytics.load = function() {
        var a = document.createElement("script");
        a.type = "text/javascript", 
        a.async = !0, a.src = "http://cdn5.bigcommerce.com/r-2b2d3f12176a8a1ca3cbd41bddc9621d2657d707/app/assets/js/vendor/bigcommerce/analytics.min.js";
        var b = document.getElementsByTagName("script")[0];
// This line still runs and loads analytics.min.js
// This line still runs and loads analytics.min.js
// This line still runs and loads analytics.min.js
        b.parentNode.insertBefore(a, b)
// ^^^ This line still runs and loads analytics.min.js
// This line still runs and loads analytics.min.js
// This line still runs and loads analytics.min.js
    }, window.bcanalytics.SNIPPET_VERSION = "2.0.8", window.bcanalytics.load();
    bcanalytics.initialize({"Fornax": {"host": "https:\/\/analytics.bigcommerce.com","cdn": "http:\/\/cdn5.bigcommerce.com\/r-2b2d3f12176a8a1ca3cbd41bddc9621d2657d707\/app\/assets\/js\/vendor\/bigcommerce\/fornax.min.js","defaultEventProperties": {"storeId": 729188,"experiments": {"shipping.eldorado.ng-shipment.recharge-postage": "on","shipping.eldorado.label_method": "on","cp2.lightsaber": "on","PMO-272.cp1_new_product_options": "on","cart.limit_number_of_unique_items": "control","cart.auto_remove_items_over_limit": "control","BIG-15465.limit_flash_messages": "control","BIG-15230.sunset_design_mode": "control","bigpay.checkout_authorizenet.live": "on","bigpay.checkout_authorizenet.live.employee.store": "control","bigpay.checkout_authorizenet.test": "on","bigpay.checkout_authorizenet.test.employee.store": "control","bigpay.checkout_stripe.live": "on","bigpay.checkout_stripe.live.employee.store": "control","bigpay.checkout_stripe.test": "on","bigpay.checkout_stripe.test.employee.store": "control","sessions.flexible_storage": "on","PMO-439.ng_payments.phase1": "control","PMO-515.ng_payments.phase2": "control","PROJECT-331.pos_manager": "control","PROJECT-453.enterprise_apps": "control","shopping.checkout.cart_to_paid": "legacy_ui","onboarding.initial_user_flow.autoprovision": "on","faceted_search.enabled": "off","faceted_search.displayed": "off","themes.previewer": "enabled"}},"defaultContext": {"source": "Bigcommerce Storefront"},"anonymousId": "24a35a36-7153-447e-b784-c3203670f644"}});
})();
</script>

window.bcanalytics.load 设法存活并加载 analytics.min.js(根据“网络”选项卡),但我无法判断脚本是否 运行 或没有。

此外,我发现这些讨厌的 HTML 行:

<script type="text/javascript" defer="" async="" src="http://tracker.boostable.com/boost.bigcommerce.js"></script>
<script type="text/javascript" async="" defer="" src="http://cdn5.bigcommerce.com/r-2b2d3f12176a8a1ca3cbd41bddc9621d2657d707/javascript/jirafe/beacon_api.js"></script>
<script type="text/javascript" async="" src="http://cdn5.bigcommerce.com/r-2b2d3f12176a8a1ca3cbd41bddc9621d2657d707/app/assets/js/vendor/bigcommerce/analytics.min.js"></script>
<script type="text/javascript" async="" src="http://www.google-analytics.com/plugins/ua/ecommerce.js"></script>

总是预先添加到第一个未注释的 <script> 开始标记,所以不幸的是,下面的 none 创造性破坏方法将起作用,因为我尝试在这些标记之前插入任何脚本将自动找到附加在它之前的讨厌的不需要的行。

如果你知道你至少可以让你的脚本先到 运行,一个(尽管很老套)解决方案就是绝对 "trash" 下一个脚本的 JS 环境,所以它有一些问题。例如:

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

一旦敌人脚本尝试使用其中一个函数,它就会崩溃。这些只是我脑海中浮现出的一些常用方法……找出它使用的是哪些,然后对它们进行核对。当然,在您自己的页面上删除您需要的任何事件可能是个问题。

假设有问题的代码与您链接到的问题的代码相似,我会简单地尝试破坏有问题的代码,使其无法执行。
从这里开始,答案依赖于另一个问题的代码,因为您没有提供任何代码。

有问题的代码依赖于分析,这在脚本开头的页面上得到了保证:

(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
})();

要破坏整个脚本并防止它 运行ning 您应该简单地分配 window.analytics 一个值,该值将与所使用的方法发生冲突。
因此,例如,您可以 运行 在有问题的脚本之前添加一个脚本,该脚本仅分配以下内容:

window.analytics = function () {};

这将导致违规脚本因类型错误而失败。

如何注入脚本?如果它是通过 document.createElement 之类的东西实现的,您可以尝试劫持该函数并在元素名称为 script:

时禁用它
var origCreate = document.createElement;
document.createElement = function (name) {
  if (name.toLowerCase() !== 'script') {
    origCreate.call(document, name);
  }
};

和其他人一样,我建议破坏恶意脚本的 js 环境,然后在需要时恢复它。

比如脚本依赖document.getElementById,你可以这样做

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

然后如果以后有需要使用document.getElementById,可以恢复回来:

document.getElementById = restore.getElementById;

我还想指出,据我所知,删除实际的脚本标签是不可能的:

  • 如果您在恶意脚本之前放入一个脚本,那么它们将不会在 DOM 中加载,因此它看不到任何要删除的内容。
  • 如果您在恶意脚本之后放置一个脚本,恶意脚本将已经被加载。

由于正在插入脚本 服务器端 ,您将无法在 JavaScript 中禁用脚本的 运行ning .但是,如果您能够在插入脚本之前和之后插入 任意文本 ,您可以尝试通过先插入以下代码来注释掉脚本标签:

  <!--

...然后是:

  -->

如果脚本在它们之间被注入,它有望导致 HTML 解析器忽略脚本。

更新:

听起来您只需要禁用此内容的 一些 ,因此将所有内容都注释掉是行不通的。但是,如果 before/after 劫持有效,您可能会将注入的脚本包装在 DOM 元素中,解析该内容,删除不需要的脚本,然后注入脚本,以便它们 运行:

之前注入这样的东西:

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

...之后是:

</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>