Tracking origin of events and DOM changes in Chrome (page or extension content script or other)

380 views
Skip to first unread message

Michael C.

unread,
Jan 18, 2017, 1:54:00 AM1/18/17
to Chromium-discuss
Hi all,

I planning on forking the Chromium project and would like to experiment with adding some additional functionality.

1) I am trying to find out if it is possible to determine if an event was originated by the page (ie. user or a loaded JavaScript file) or by a extension's content script. 
2) I'm also wondering if it is possible to track where changes to the DOM originated from (page or content script again). 

I realize there are other methods to fire events (such as through applications and bookmarklets) but extension content scripts are my real focus. I believe 2) might be possible due to the Isolated Worlds principle that exists for Chrome extensions (whereby content scripts and pages share the DOM but not the JavaScript objects which represent it). However, 1) seems less likely to already exist as content scripts and page JavaScript run in the same process.

In either case, any pointers to where to look for this code would be much appreciated.

Kind regards,
Michael C.




PhistucK

unread,
Jan 18, 2017, 2:00:41 AM1/18/17
to mik...@gmail.com, Chromium-discuss
I would imagine it will not be hard to add that information to DOM changes and events (due to the isolated world concept), however, extensions can add scripts to the context of the page (add a <script> to the page) as well, which makes it pretty much impossible to know whether the event that this added <script> created came from extension code, or page code.

So, basically, if you are only interested in content script (and not <script> added to the page by the content script) originated events and DOM changes, I imagine that would be possible (unless you consider events that were artificially fired by the page itself to also be page originated and not content script originated, even though they cause content script code to run and do stuff like DOM changes and fire more events).

Somehow., I do not think that would be enough for you. :)


PhistucK

--
--
Chromium Discussion mailing list: chromium...@chromium.org
View archives, change email options, or unsubscribe:
http://groups.google.com/a/chromium.org/group/chromium-discuss

---
You received this message because you are subscribed to the Google Groups "Chromium-discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to chromium-discuss+unsubscribe@chromium.org.

Michael C.

unread,
Jan 18, 2017, 8:18:14 AM1/18/17
to Chromium-discuss, mik...@gmail.com
On Wednesday, 18 January 2017 07:00:41 UTC, PhistucK wrote:
I would imagine it will not be hard to add that information to DOM changes and events (due to the isolated world concept), however, extensions can add scripts to the context of the page (add a <script> to the page) as well, which makes it pretty much impossible to know whether the event that this added <script> created came from extension code, or page code.

I was under the impression that scripts added in the context of the page also abide by the isolated worlds concept. If not, the same vulnerabilities would exist as those if the content script did not abide by the isolated worlds concept. I may be mistaken!
 
So, basically, if you are only interested in content script (and not <script> added to the page by the content script) originated events and DOM changes, I imagine that would be possible (unless you consider events that were artificially fired by the page itself to also be page originated and not content script originated, even though they cause content script code to run and do stuff like DOM changes and fire more events).

I wouldn't mind if an event was artificially fired by the page (and page originated), which then cause events to be fired by content script code (as long as the events fired by the content script originated by the content script).
 

Somehow., I do not think that would be enough for you. :)


PhistucK

On Tue, Jan 17, 2017 at 9:47 PM, Michael C. <mik...@gmail.com> wrote:
Hi all,

I planning on forking the Chromium project and would like to experiment with adding some additional functionality.

1) I am trying to find out if it is possible to determine if an event was originated by the page (ie. user or a loaded JavaScript file) or by a extension's content script. 
2) I'm also wondering if it is possible to track where changes to the DOM originated from (page or content script again). 

I realize there are other methods to fire events (such as through applications and bookmarklets) but extension content scripts are my real focus. I believe 2) might be possible due to the Isolated Worlds principle that exists for Chrome extensions (whereby content scripts and pages share the DOM but not the JavaScript objects which represent it). However, 1) seems less likely to already exist as content scripts and page JavaScript run in the same process.

In either case, any pointers to where to look for this code would be much appreciated.

Kind regards,
Michael C.




--
--
Chromium Discussion mailing list: chromium...@chromium.org
View archives, change email options, or unsubscribe:
http://groups.google.com/a/chromium.org/group/chromium-discuss

---
You received this message because you are subscribed to the Google Groups "Chromium-discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to chromium-discu...@chromium.org.

PhistucK

unread,
Jan 18, 2017, 11:44:35 AM1/18/17
to Michael Cypher, Chromium-discuss
<script> added by content script does not have access to extension APIs, it simply runs in the context of the page just like any other script.


PhistucK

To unsubscribe from this group and stop receiving emails from it, send an email to chromium-discuss+unsubscribe@chromium.org.

Torne (Richard Coles)

unread,
Jan 18, 2017, 11:57:21 AM1/18/17
to phis...@gmail.com, Michael Cypher, Chromium-discuss
Yeah, there is no difference between a <script> tag that was originally there in the page, and a <script> tag inserted by a content script. The isolated world only applies to the JS environment; the DOM itself is shared, and inserted tags do not have any notion of which world inserted them.

Michael C.

unread,
Jan 18, 2017, 12:19:22 PM1/18/17
to Chromium-discuss, phis...@gmail.com, mik...@gmail.com
From my understanding, although they have the same world, they have different JavaScript objects that refer to those DOM objects ("A content script can read or modify a website’s DOM, but the content script and website have separate JavaScript heaps with their own DOM objects" in https://www.usenix.org/system/files/conference/usenixsecurity12/sec12-final177_0.pdf). Does the code inserted by a <script> tag from a content script (extension) share the same JavaScript DOM objects as the original page? 

If not, it seems like they might be running in slightly different environments and this might be helpful in establishing that events that they fire originated from an extension. I realize the inserted tags do not know what inserted them, but the JavaScript that runs as a consequence might (due to it's JavaScript DOM objects)?

PhistucK

unread,
Jan 18, 2017, 12:21:39 PM1/18/17
to Michael C., Chromium-discuss
The answer is yes. They share the same context, DOM, JavaScript heap, everything. It is just like the page added that <script>.


PhistucK

Torne (Richard Coles)

unread,
Jan 18, 2017, 12:42:40 PM1/18/17
to phis...@gmail.com, Michael C., Chromium-discuss
The javascript object for a particular <script> tag is a different object in each world. However, this is true for *all* script tags, no matter who added them. It's effectively two sets of "bridges" from the JS environment to the native DOM data structures inside the browser.

No matter which side adds a particular tag, the result is just that the page contains that tag, and <script> tags in a page run in the page's environment, always.

Michael C.

unread,
Jan 18, 2017, 1:01:33 PM1/18/17
to Chromium-discuss, phis...@gmail.com, mik...@gmail.com
This is what I thought. It seems like it might be possible to add an origin for each world. I wonder how these objects are initialized and if it's possible to add an additional world-specific object that represents information about the object when the DOM object is initialized - before the <script> tag is run in the same environment.

Do you happen to know where to look regarding where the DOM objects that point to the native DOM data structures in the browser are initialized?

Michael C.

unread,
Feb 9, 2017, 12:35:17 PM2/9/17
to Chromium-discuss, phis...@gmail.com, mik...@gmail.com
Hi Richard,

I've been doing some more research and I was wondering: if an extension inserts a <script> tag, is it run in the same execution context as the page or other <scripts> - would it not have a different security origin (namely the origin given to the extension)?

Thanks

Torne (Richard Coles)

unread,
Feb 9, 2017, 12:48:22 PM2/9/17
to mik...@gmail.com, Chromium-discuss, phis...@gmail.com
It runs in the same execution context as the page, and therefore has the same origin as the page. Individual scripts do not have an origin; only entire page contexts do.

Michael C.

unread,
Feb 9, 2017, 2:59:37 PM2/9/17
to Chromium-discuss, mik...@gmail.com, phis...@gmail.com
Hi Richard,

Thanks for answering that. I ran my own experiment and my reached the same answer. 

I think my only possibility to catch extension actions is to first transpile the extension code (before running it) and replacing function calls like:

elem.click();

to

elem.dispatchEvent(new Event("click", {fromExtension: true}));

And storing this flag in the Event object. I will give this a shot and let you know how it goes. Thanks for your help.

Michael 

proberge

unread,
Feb 16, 2017, 1:53:48 AM2/16/17
to Chromium-discuss, mik...@gmail.com, phis...@gmail.com
Hi Michael,

I tried doing something similar last year. My work was focused on scripts and page content injected on the page by extensions and trying to transitively keep track of the origin. 

My patchset is available here. It was never submitted due to the code complexity increase and correctness issues.
If you're working on a fork and don't care about the origin tracking being correct 100% of the time, this might be a good start.

If I remember correctly, it was able to handle an extension injecting a script tag on page, where the script tag registered some events (ex. timer, click) which resulted in another script injection or a div creation on the page; it correctly identified the div as extension-originating. However, there are some more fancy ways of manipulating the DOM that my patchset could not handle without huge complexity and performance costs.

Hope this helps!
PA

Michael C.

unread,
Feb 16, 2017, 3:55:27 PM2/16/17
to Chromium-discuss, mik...@gmail.com, phis...@gmail.com
Hi PA,

This is really really cool and useful. I hadn't thought about keeping track of the original origin and this seems much simpler than I imagined. I'll try using this and the DOM to determine if events or DOM actions originate from a particular extension. I'll let you know how I get on! 

Out of curiosity, what are the other fancy ways of manipulating the DOM to avoid this propagation (if you remember)? I see multiple comments regarding frames and message passing that may be related?

Thank you!
Michael

proberge

unread,
Feb 16, 2017, 4:04:28 PM2/16/17
to Chromium-discuss, mik...@gmail.com, phis...@gmail.com
I think Promises and MutationObservers didn't work. I don't recall other cases at the moment; note that I have very limited knowledge of DOM manipulation, so I'm probably missing a lot of stuff.

You might be able to get 90% of the way with the original origin code; I assume most extensions modify the page in a straightforward way. As you discover other ways, you could handle them through transpiling the extension or by adding more originWorldScopes in various WebKit code locations. 

Michael C.

unread,
May 4, 2017, 5:57:48 PM5/4/17
to Chromium-discuss, mik...@gmail.com, phis...@gmail.com
Hi PA,

I've trying to demonstrate how origin world propagation works for Timers and does not work for Promises.

Essentially, my content script is injecting a script tag and the script tag is creating a new Timer/Promise that in turn injects another script tag. Unfortunately, I cannot demonstrate the double script tag injection due to CSP. If CSP is enabled, do we even need to keep a stack of worlds? After, all the worst is that it'll be one world deep (assuming a strong enough CSP)?


Thanks for your help,
Michael

proberge

unread,
May 23, 2017, 11:45:59 AM5/23/17
to Chromium-discuss, mik...@gmail.com, phis...@gmail.com
Hi Michael,

Sorry for the delayed response. 

I might be misunderstanding your issue, but you may be able to demonstrate the double injection by in-lining code (with scriptElement.innerText) instead of loading it from an external resource through scriptElement.src.

PhistucK

unread,
May 23, 2017, 12:27:56 PM5/23/17
to proberge, Chromium-discuss, Michael Cypher
scriptElement.textContent is more likely to be what you intended. Not innerText (which triggers layout).


PhistucK

Michael C.

unread,
May 23, 2017, 12:32:37 PM5/23/17
to Chromium-discuss, prob...@chromium.org, mik...@gmail.com
I managed to solve this using scriptElement.src = … (where I assign a code instead of a url).

sn22...@gmail.com

unread,
Jun 30, 2020, 12:53:43 PM6/30/20
to Chromium-discuss, Michael C., proberge
Hi! 
I'm also looking for any API or method to figure out the origin of events, which means that I would like to find out where the event is created (page or other injected script).

It's been a long time from this conversations, do you solve this problem?

Reply all
Reply to author
Forward
0 new messages