Can a webpage detect a tampermonkey userscript?

2020-06-16 04:36发布

问题:

My question is sort of two-fold. First, how the sandbox model works, how it impacts the userscript, what is accessible / seen from the webpage and userscript point of view, and if using a different sandbox model affects the page being able to notice your script being injected into the page (or not). Second, how scripts are injected into the page, and can the page detect it?

First

From what I can see, when you use @grant none, the sandbox is disabled and you will have access to the webpage and its javascript. IF you make any changes to the javascript and/or DOM, it is possibly detectable by the page.

My understanding is, if you use @grant unsafeWindow, your script will be isolated in its own js context, anything you do to window will NOT be seen by the webpage, BUT you can access the webpage and javascript through unsafeWindow. You will have regular access to the DOM, e.g. document returns the regular page document rather than you needing to say unsafeWindow.document. Obviously, any changes you make to the DOM or page js context (e.g. unsafeWindow.foo = 'bar';) will still be detectable. The reason it is unsafe is not because of being detected or not, but because you are able to potentially give the untrusted page access to privileged GM_* functions in this mode, (which are not granted in regular mode, which means that @grant GM_* for any function will isolate the js context, and you'll lose access to the page's js context unless you @grant unsafeWindow)

Second

How are scripts injected into the page? Is it possible that the webpage can notice the userscript injection (assuming the userscript modifies NOTHING on the page).

For example, if a script was injected using a script tag, I think the page could possibly notice the script injection, even get a look at its code?

Does the sandbox model have any role in the way this happens, and make it "safer" to not be seen? For example, if the js contexts are isolated if you use @grant unsafeWindow, then perhaps the js on the webpage can't even see any userscript load event, making @grant unsafeWindow fundamentally safer, UNLESS you go modifying the DOM or unsafeWindow of course.

I'm also assuming that there's no leak of special functions, objects, properties, etc (such as GM_info to the webpage which would betray the existence of tampermonkey?). Neither in @grant none mode or @grant unsafeWindow mode (provided you didn't leak anything to the page)

This lets me feel that unsafeWindow is actually safer in terms of not being detected (because the js contexts are isolated), as long as you don't go modifying anything (and especially DON'T expose privileged GM_* functions to unsafeWindow). For example, if you used an eventListener on @grant none mode, it may possibly be detected, but if you use it in @grant unsafeWindow mode, it may not be detected because of the isolation? Furthermore, IF it was possible for a page to detect the userscript loading (I don't know if this is actually possible or not), it wouldn't know if the js contexts are isolated

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

Are any of my above thoughts above incorrect in any area, and if so, how does it actually work?

Update

A little information for clarification:

A userscript only reads information passively from the page (perhaps using a MutationObserver). It doesn't alter anything in any way, does not use any js libraries (neither from the userscript nor from the webpage) no ajax calls, no script nodes, definitely no clicks, etc. The script MAY read some information from JS vars on the page (let's assume those vars and functions are not booby trapped), as well as using a WebSocket (internal service). Using an IIFE too. So the question mostly is, is tampermonkey in and of itself (and if it runs a page script) detectable?

In this answer: https://stackoverflow.com/a/8548311 I can rule out 1, 4, 5, 6, and 7; probably 2 and 3 as well, but I don't know if tampermonkey in and of itself would affect any of these

回答1:

Browsers and Greasemonkey/Tampermonkey/Violentmonkey have (mostly) improved how they do injection, scoping, and sand-boxing. Userscripts are not injected using ordinary <script> tags (although your script may need to create such tags in some occasions).

In fact, there's almost no need to use an IIFE nowadays.

But, in addition to the detection methods in the previously linked question:

  1. In @grant none mode, if you @require a library that copies itself to window scope, the page can see it. Most libraries do not do that, but one that does is jQuery.
  2. Tampermonkey actually provides the installed script version to sites that are whitelisted in the advanced settings. This is mainly for script hosts like greasyfork.org.
  3. I don't know if a page can detect WebSockets in use by a userscript. I doubt it.

Bottom line, is for a "read only" userscript, that does not require global libraries in @grant none mode, the page cannot detect it.
(Unless the page is greasyfork.org, etc., and you have the Allow communication with cooperate pages setting at the default value.)

If you discover some leak whereby a page can detect a "passive" script, let us know and chances are it can get plugged.



回答2:

As mentioned by the answer https://stackoverflow.com/a/8548311 if you do something of the likes it is definitely detectable. But, depending on what you want to do with the tampermonkey script, it will be easier or more difficult to detect, and in some cases impossible.

From what you are asking, it seems like what you want to make is just invoke an IIFE from the page, and just stop there, "let's say it just reads information".

This is really tricky to capture, and usually for this, the page should have to compare profilers and execution times and such of other users against you, or some other funky things, and there is no real easy way to find out if the user executed extra JS in the page (as long as you use an IIFE) that has NO SIDE EFFECT. I am not saying that it is 100% undetectable, but let's say it's really really tricky.

If you are going to modify the DOM, make API calls to an external or internal service, fake movements of the user or other things of this kind, you are going to be detected. So, it depends on what you want to do with the page, but you can be detected "quite easily".

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

Yes a page can detect these in those cases in which you leave a trace in the page (as defined above). Keep in mind that this will happen only there is a reason for the page to want to know if that is happening. Also keep in mind that no page will implement something like this just for the sake of it, so don't expect normal pages to complain about this.