网页可以检测到篡改用户脚本吗?

Can a webpage detect a tampermonkey userscript?

我的问题有两个方面。 首先,沙箱模型如何工作,它如何影响用户脚本,从网页和用户脚本的角度可以访问/看到什么,以及如果使用不同的沙箱模型会影响页面能够注意你的脚本被注入页面(或没有)。 其次,页面是如何注入脚本的,页面能检测到吗?

第一

据我所知,当您使用 @grant none 时,沙盒被禁用,您将可以访问该网页及其 javascript。如果您对 javascript and/or DOM 进行任何更改,它可能会被页面检测到。

我的理解是,如果你使用 @grant unsafeWindow,你的脚本将被隔离在它自己的 js 上下文中,你对 window 所做的任何操作都不会被网页看到,但你可以访问网页和 javascript 到 unsafeWindow。您将可以定期访问 DOM,例如document returns 常规页面文档而不是你需要说 unsafeWindow.document。显然,您对 DOM 或页面 js 上下文(例如 unsafeWindow.foo = 'bar';)所做的任何更改仍然可以检测到。它是 unsafe 的原因不是因为是否被检测到,而是因为您可以在此模式下潜在地授予不受信任的页面访问特权 GM_* 功能的权限,(在常规模式下未授予,这意味着任何函数的 @grant GM_* 都会隔离 js 上下文,并且您将无法访问页面的 js 上下文,除非您 @grant unsafeWindow)

第二

如何将脚本注入页面?网页是否可以注意到用户脚本注入(假设用户脚本在页面上没有修改任何内容)。

例如,如果脚本是使用script标签注入的,我认为页面可能会注意到脚本注入,甚至看一下它的代码?

沙盒模型是否在这种情况发生的过程中发挥了作用,并使其“更安全”不被人看到?例如,如果使用 @grant unsafeWindow 时 js 上下文是隔离的,那么网页上的 js 可能甚至看不到任何用户脚本加载事件,从而使 @grant unsafeWindow 从根本上更安全,除非你去修改 DOM 或 unsafeWindow 当然。

我还假设没有特殊功能、对象、属性等的泄漏(例如 GM_info 到网页,这会泄露 tampermonkey 的存在?)。无论是 @grant none 模式还是 @grant unsafeWindow 模式(前提是您没有向页面泄漏任何内容)

这让我觉得 unsafeWindow 在不被发现方面实际上更安全(因为 js 上下文是隔离的),只要你不去修改任何东西(尤其是不要暴露unsafeWindow 的特权 GM_* 函数)。 例如,如果你在@grant none模式下使用eventListener,可能会检测到,但如果你在@grant unsafeWindow模式下使用,则可能检测不到因为隔离?此外,如果页面有可能检测到用户脚本加载(我不知道这是否真的可能),它就不知道 js 上下文是否被隔离

简而言之,如果您不背叛它,页面能否检测到您的用户脚本或篡改猴子的存在?

我上面的任何想法在任何方面都是不正确的吗?如果是这样,它实际上是如何工作的?

更新

澄清一点信息:

用户脚本仅从页面被动读取信息(可能使用 MutationObserver)。它不会以任何方式改变任何东西,不使用任何 js 库(既不来自用户脚本也不来自网页)没有 ajax 调用,没有脚本节点,绝对没有点击等。脚本可能会读取一些信息来自页面上的 JS 变量(假设这些变量和函数没有陷阱),以及使用 WebSocket(内部服务)。也使用 IIFE。所以问题主要是,tampermonkey 本身(如果它运行页面脚本)是否可检测?

在这个回答中: 我可以排除 1、4、5、6 和 7;可能还有 2 和 3,但我不知道 tampermonkey 本身是否会影响其中任何一个

正如答案 中提到的那样,如果您执行类似的操作 它肯定是可以检测到的。 但是,这取决于您要对 tampermonkey 脚本执行的操作, 会更容易或更难检测,在某些情况下不可能.

根据您的要求,您似乎只是想从页面调用 IIFE,然后就此打住,"let's say it just reads information"。

这真的很难捕捉,通常为此,页面必须比较分析器和执行时间等其他用户与您的情况,或其他一些时髦的东西,并且没有真正简单的方法可以找到如果用户在页面中执行额外的 JS(只要您使用 IIFE)NO SIDE EFFECT。我并不是说它 100% 无法检测到,但可以说它真的非常棘手。

如果您要修改DOM,请API调用外部或内部服务、虚假用户移动或其他在这种情况下,你会被发现。所以,这取决于你想对页面做什么,但是你可以被检测到"quite easily".

In a brief summary, can a page detect either your userscript's or tampermonkey's existence IF you don't betray it?

是的,在您在页面中留下痕迹(如上定义)的情况下,页面可以检测到这些。请记住,只有当页面有理由想知道是否发生这种情况时,才会发生这种情况。还要记住,没有页面会为了它而实现这样的东西,所以不要指望普通页面会抱怨这个。

浏览器和 Greasemonkey/Tampermonkey/Violentmonkey 已经(大部分)改进了它们进行注入、范围界定和 sand-boxing 的方式。用户脚本不会使用普通的 <script> 标签注入(尽管在某些情况下您的脚本可能需要创建此类标签)。

事实上,现在

但是,除了previously linked question中的检测方法:

  1. @grant none模式下,如果你@require一个库将自身复制到window范围,页面可以看到它。大多数图书馆不这样做,但是 jQuery.
  2. Tampermonkey actually provides the installed script version 到在高级设置中列入白名单的站点。这主要针对像 greasyfork.org.
  3. 这样的脚本宿主
  4. 我不知道页面是否可以检测到用户脚本正在使用的 WebSocket。我怀疑。

最重要的是,对于 "read only" 用户脚本require 全局库不处于 @grant none 模式,页面检测不到。
(除非页面是 greasyfork.org 等,并且您将 Allow communication with cooperate pages 设置为默认值。)

如果您发现页面 可以 检测到 "passive" 脚本的漏洞,请告诉我们,它很可能会被堵塞。

Amazon 实现了等待 3 或 4 秒然后检索所有控制台信息的功能。

这是看起来的样子

{
    "logs": [{
        "level": "error",
        "message": "Cannot set property 'checked' of null",
        "error": {
            "errorMessage": "Cannot set property 'checked' of null",
            "errorName": "TypeError",
            "errorStackTrace": "TypeError: Cannot set property 'checked' of null\n    at storageUpdate (chrome-extension://dhdgffkkebhmkfjojejmpbldmpobfkfo/userscript.html?name=myUserscript).user.js&id=ea4d27bb-1f9a-44e5-847c-2f61122b4d75:14467:86)\n    at Window.configModal (chrome-extension://dhdgffkkebhmkfjojejmpbldmpobfkfo/userscript.html?name=myUserscript).user.js&id=ea4d27bb-1f9a-44e5-847c-2f61122b4d75:14488:29)\n    at <anonymous>:3:100\n    at E.z.<computed> (eval at exec_fn (:1:157), <anonymous>:43:442)"
        },
        "context": {
            "logTime": 1610058101393
        }
    }]
}

这是新的,无论他们是否针对我,他们都可以清楚地看到 tampermonkey 正在工作:

chrome-扩展名://dhdgffkkebhmkfjojejmpbldmpobfkfo/