WebExtensions: access to cross-origin document.styleSheets[…].cssRules from content scripts should honour "permissions" from manifest.json
Categories
(WebExtensions :: General, enhancement, P5)
Tracking
(Not tracked)
People
(Reporter: m_khvoinitsky, Assigned: twisniewski)
Details
(Whiteboard: [design-decision-approved][dev-ux])
Attachments
(2 files)
1.20 KB,
patch
|
Details | Diff | Splinter Review | |
932 bytes,
application/zip
|
Details |
Comment 1•7 years ago
|
||
Reporter | ||
Comment 2•7 years ago
|
||
Updated•7 years ago
|
Comment 3•7 years ago
|
||
Reporter | ||
Comment 4•7 years ago
|
||
Comment 5•7 years ago
|
||
Comment 6•7 years ago
|
||
Comment 7•7 years ago
|
||
Comment 8•7 years ago
|
||
Comment 9•7 years ago
|
||
Comment 10•7 years ago
|
||
Comment 11•7 years ago
|
||
Updated•7 years ago
|
Updated•7 years ago
|
Updated•7 years ago
|
Updated•6 years ago
|
Comment 12•6 years ago
|
||
Updated•6 years ago
|
Assignee | ||
Comment 13•6 years ago
|
||
Updated•6 years ago
|
Reporter | ||
Comment 14•5 years ago
|
||
Any update on this?
Comment 15•4 years ago
|
||
Not sure if intended or not, but it seems that a Firefox extensions with "<all_urls>" permissions can read any cross-site stylesheet, provided that it's either imported through the @import directive or a <link> element with the @crossOrigin attribute set to "anonymous".
No need for the server to cooperate, i.e this works on Firefox even if the response contains no Access-Control-Allow-Origin header, as demonstrated by the attached extension.
This does NOT work for Chromium, though, which requires the aforementioned header to be either "*" or include the origin of the content page.
Updated•3 years ago
|
Comment 16•3 years ago
•
|
||
Hi Shane,
Thomas asked me if we can provide our opinion about this issue and in particular the approach he proposed in comment 13.
As brief a summary:
- This would be helpful for the webcompat team work (it allows Thomas' "Testcase Reducer" addon to work on more sites) and Thomas would be willing to help on this, after we have confirmed we want to proceed.
- It looks that we marked it design-decision-approved at the time, but given that it was "quite some time ago" I wanted to ask you explicitly if we want to add it to the bugs to discuss in our next triage (or in our next design decision triage meeting first).
- From a quick look to the previous comments Thomas comment 13 seems to match the requirements ("providing to the content script access to stylesheet related to origin that are allowed to the extension based on its host permissions" as mentioned in comment 6 , and "doing it for this specific scenario and not for everything at once" as mentioned in comment 11)
- Another engineer from the team maintaining those internals should be also providing their perspective (either right after confirmed we are ok or as part review and signing off phases)
Comment 17•3 years ago
|
||
Hello. Chiming in as the maintainer of react-to-print
, a. library that allows a React user to print any sub-component (DOM Element). I recently had a bug report that seems to be caused by this issue, with Firefox blocking access to sheet.cssRules
, though I am not using WebExtensions. The pseudo version of what the library does is this, which is basically the library finding all styles on the page and copying them to be inserted into an iframe
that is used for the actual printing:
const printWindow = document.createElement("iframe");
const domDoc = printWindow.contentDocument || printWindow.contentWindow?.document;
const headEls = document.querySelectorAll("style, link[rel='stylesheet']");
for (let i = 0, headElsLen = headEls.length; i < headElsLen; ++i) {
const node = headEls[i];
if (node.tagName === "STYLE") {
const newHeadEl = domDoc.createElement(node.tagName);
const sheet = (node as HTMLStyleElement).sheet as CSSStyleSheet;
if (sheet) {
let styleCSS = "";
// Throws: `Uncaught DOMException: CSSStyleSheet.cssRules getter: Not allowed to access cross-origin stylesheet`
for (let j = 0, cssLen = sheet.cssRules.length; j < cssLen; ++j) {
if (typeof sheet.cssRules[j].cssText === "string") {
styleCSS += `${sheet.cssRules[j].cssText}\r\n`;
}
}
newHeadEl.setAttribute("id", `react-to-print-${i}`);
newHeadEl.appendChild(domDoc.createTextNode(styleCSS));
domDoc.head.appendChild(newHeadEl);
}
}
}
If this is not the right thread for me to be commenting on please let me know and I can do so elsewhere or create a new issue. Thank you.
Comment 18•3 years ago
|
||
Rob, I've no issue with this in general, though if it's not something generally allowed (ie other browsers) I think we should consider whether it is restricted to privileged addons. Do you have insight into what chrome does here and why they took whatever approach they took?
Comment 19•3 years ago
|
||
(In reply to Matthew Herbst from comment #17)
Hello. Chiming in as the maintainer of
react-to-print
, a. library that allows a React user to print any sub-component (DOM Element). I recently had a bug report that seems to be caused by this issue, with Firefox blocking access tosheet.cssRules
, though I am not using WebExtensions.
(...)
If this is not the right thread for me to be commenting on please let me know and I can do so elsewhere or create a new issue. Thank you.
Your report is unrelated to extensions, and intended behavior. The stylesheet examples that you've linked from https://github.com/gregnb/react-to-print/issues/429#issuecomment-974979427 are cross-origin stylesheets. Cross-origin stylesheets cannot be read by scripts because that would be a security issue.
In your github comment you're also referring to X-Content-Type-Options: nosniff
; this feature is associated with CORB (cross-origin read blocking), and a stronger security restriction, in preventing not only JS code from reading the stylesheet, but even preventing the process from attempting to load it at all.
CORB provides a bridge to the expectations for behaviors in content scripts (which relates to Shane's question):
(In reply to Shane Caraveo (:mixedpuppy) from comment #18)
Rob, I've no issue with this in general, though if it's not something generally allowed (ie other browsers) I think we should consider whether it is restricted to privileged addons. Do you have insight into what chrome does here and why they took whatever approach they took?
In Chrome's early extension framework design, host permissions unlocked the ability to perform cross-origin read/fetch requests from content scripts. This feature was removed in order to support the enforcement of CORB in the context of Site isolation (https://www.chromium.org/Home/chromium-security/extension-content-script-fetches). We're planning to do the same in Firefox (bug 1578405).
In general we should try to refrain from using permissions
to relax security restrictions in content scripts, especially if it hinders our ability to enforce security with Site isolation.
One could however make a case for reading .cssRules
, because even with Site isolation, a valid stylesheet is already read/parsed in the process.
On the other hand, the ability to read .styleSheets[...].cssRules
could inadvertently be abused by web pages.
If we want to support this feature at all, I think we should require host permissions AND a new extension permission. Or introduce this feature in the chrome.dom
namespace. Anyone interested in this feature in a cross-browser way could file a request at https://github.com/w3c/webextensions.
I ran the following test case to confirm that Chrome currently refuses to offer access to .cssRules
in content scripts:
- Start Chromium with an extension that has a content script at
<all_urls>
. - Visit https://example.com
- Insert an external stylesheet via the devtools:
s = document.createElement('link'); s.type = "text/css"; s.rel = "stylesheet"; s.href = "https://robwu.nl/style.css"; document.head.prepend(s);
- Switch the devtools context to the content script and run
document.styleSheets[0].cssRules
to access the rules.
Result:
- Uncaught DOMException: Failed to read the 'cssRules' property from 'CSSStyleSheet': Cannot access rules.
Assignee | ||
Comment 20•3 years ago
|
||
@Rob: would it be better/easier to just support Chrome's chrome.devtools.inspectedWindow.getResources
method to get at all of the CSS stylesheets? Then we could presumably get at their text content with the related getContent
and parse that using a <style>
element to get at the rules.
Comment 21•3 years ago
|
||
(In reply to Thomas Wisniewski [:twisniewski] from comment #20)
@Rob: would it be better/easier to just support Chrome's
chrome.devtools.inspectedWindow.getResources
method to get at all of the CSS stylesheets?
Easier? Not likely. Possible slightly more feasible if there is already something that keeps track of the loaded resources.
Then we could presumably get at their text content with the related
getContent
and parse that using a<style>
element to get at the rules.
... which could result in more network activity when the stylesheet references external resources, e.g. external stylesheets with @import
.
If you're already willing to perform additional network activity, then the work-around mentioned by Giorgio in comment 15 could work. It is basically forcing the request to be CORS-enabled, and triggers the code path that allows the extension's host permissions to be effective. I guess via https://searchfox.org/mozilla-central/rev/65d4d3399afa79c8de5a0cc11752d2ba7c31edc1/dom/security/nsContentSecurityManager.cpp#1241-1243 + https://searchfox.org/mozilla-central/rev/65d4d3399afa79c8de5a0cc11752d2ba7c31edc1/netwerk/protocol/http/nsCORSListenerProxy.cpp#903-904
Thomas/Giorgio - what are your use cases, and why are getComputedStyle
+ browser.tabs.insertCSS
insufficient?
If there is a clear need for this API we could raise an issue at the WECG to solicit additional feedback.
Assignee | ||
Comment 22•3 years ago
•
|
||
My use case is that the Testcase Reducer [1] addon currently cannot always grab the styles for iframes, and this causes it to break in many cases. Basically it needs to gather all of the CSS text which applies to whatever parts of the page it is reducing, not just the computed styles.
I suspect that I can use Giorgio's workaround (I'm already using it, just without the <anonymous> trick), but I was hoping to avoid having to use it entirely (to not trigger any page scripts looking for DOM changes and the like).
[1] https://addons.mozilla.org/en-US/firefox/addon/testcase-reducer/
Updated•3 years ago
|
Updated•2 years ago
|
Description
•