【问题标题】:Firefox doesn't respect Object.defineProperty() from a Greasemonkey script?Firefox 不尊重 Greasemonkey 脚本中的 Object.defineProperty()?
【发布时间】:2019-06-26 15:33:44
【问题描述】:

我正在编写一个用户脚本来防止网站设置document.body.innerHTML,这是网站检测到广告屏蔽的典型​​标志:

(function() {
    'use strict';
    console.log("Loading ...");

    Object.defineProperty(document.body, "innerHTML", {
        set: function() {
            console.log("malicious activity detected");
            throw "Don't try to fool my adblock!";
        }
    });
    console.log("Test setting document.body ...");
    try {
        document.body.innerHTML = "";
    } catch (e) {
        console.log(e);
    }
}) ();

上述用户脚本适用于 Chrome+Tampermonkey。但它在 Firefox+Greasemonkey-4 上的行为很奇怪。

控制台的输出是:

加载中...
测试设置 document.body ...
检测到恶意活动
不要试图欺骗我的广告拦截!

所以用户脚本加载成功,setter 也成功挂钩。但是在加载后我在控制台中尝试:

document.body.innerHTML = ""

它只是设置innerHTML 而不会抛出错误,就好像没有安装钩子一样。我已经尝试了所有@run-at 选项,但都不起作用。


OTAH,如果我在控制台中使用Object.defineProperty(),那么它会按预期工作。因此我得出结论,Firefox 不尊重用户脚本中的Object.defineProperty()

您也可以尝试访问此网站:https://connectwww.com。在 Chrome 中的 Tampermonkey 中安装上述用户脚本后,网站上的 adblock-detection 被成功拦截。但是用户脚本在 Firefox+Greasemonkey 上不起作用。

为什么 Firefox 尊重用户脚本中的 Object.defineProperty()?有什么解决方法吗?

附注:

一些著名的用户脚本,如 anti-adblock-killer 也适用于 Chrome,但不适用于上述测试网站的 Firefox,我想这是由于相同的原因。

【问题讨论】:

    标签: javascript firefox tampermonkey adblock greasemonkey-4


    【解决方案1】:

    Greasemonkey 4 即使在 @grant none 模式下也会对您的脚本进行沙箱处理。 (这是Greasemonkey 4 唯一比 Tampermonkey 或 Violentmonkey 做得更好的事情。)

    所以您的脚本正在设置innerHTML 的脚本范围/副本。
    在与目标页面范围共享的 Tampermonkey 中,但在 Greasemonkey 中,这两个范围更合适地分开。所以页面范围(和默认控制台)看不到变化。

    在这种情况下,我不认为the unsafeWindow methods 可以工作; 您必须注入覆盖代码

    这是一个适用于 Greasemonkey 4+ 和 Tampermonkey 的脚本(也应该适用于 Violentmonkey,但我没有对此进行测试)。它适用于 Chrome 和 Firefox:

    // ==UserScript==
    // @name     _Overriding Target page functions can be tricky with GM 4
    // @match    *://YOUR_SERVER.COM/YOUR_PATH/*
    // @grant    none
    // @run-at   document-start
    // ==/UserScript==
    /* eslint-disable no-multi-spaces */
    
    console.log("Loading ...");
    
    function overrideIt () {
        //-- Necessary check because of scope madness in TM, VM, etc.
        if (document.body.innerHTML) {
            Object.defineProperty (document.body, "innerHTML", {
                set: function () {
                    var scopeStr = (typeof GM === "object"  &&  GM.info) ? "script" : "page";
                    console.log (`Malicious activity detected - ${scopeStr} scope`);
                    throw "Don't try to fool my adblock!";
                }
            } );
        }
    }
    overrideIt ();
    
    if (typeof unsafeWindow === "object") {
        console.log ("unsafeWindow detected.");
        addJS_Node (null, null, overrideIt);
    }
    
    console.log ("Test setting document.body ...");
    try {
        document.body.innerHTML = "";
    } catch (e) {
        console.log ("Caught: ", e);
    }
    
    //-- addJS_Node is a standard(ish) function
    function addJS_Node (text, s_URL, funcToRun, runOnLoad) {
        var D                                   = document;
        var scriptNode                          = D.createElement ('script');
        if (runOnLoad) {
            scriptNode.addEventListener ("load", runOnLoad, false);
        }
        scriptNode.type                         = "text/javascript";
        if (text)       scriptNode.textContent  = text;
        if (s_URL)      scriptNode.src          = s_URL;
        if (funcToRun)  scriptNode.textContent  = '(' + funcToRun.toString() + ')()';
    
        var targ = D.getElementsByTagName ('head')[0] || D.body || D.documentElement;
        targ.appendChild (scriptNode);
    }
    

    【讨论】:

      猜你喜欢
      • 2012-04-25
      • 2016-02-20
      • 1970-01-01
      • 2015-07-04
      • 1970-01-01
      • 2013-07-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多