Closed Bug 1411641 Opened 7 years ago Closed 6 months ago

CSP 'sandbox' directive prevents content scripts from matching, due to unique origin, breaking also browser features [Screenshots]

Categories

(WebExtensions :: General, defect, P2)

defect

Tracking

(firefox128 fixed)

RESOLVED FIXED
128 Branch
Tracking Status
firefox128 --- fixed

People

(Reporter: arantius, Assigned: robwu)

References

(Blocks 3 open bugs)

Details

(Keywords: dev-doc-complete, Whiteboard: [addons-jira])

Attachments

(6 files)

User Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:56.0) Gecko/20100101 Firefox/56.0 Build ID: 20171003101214 Steps to reproduce: NOTE this may sound like bug #1267027 but it is not. More context: https://github.com/greasemonkey/greasemonkey/issues/2631 1) Install Greasemonkey 4.0alpha8 ( https://addons.mozilla.org/en-US/firefox/addon/greasemonkey/versions/beta?page=1#version-4.0alpha8 ) 2) Navigate to https://gist.github.com/arantius/f6fd80b1efad368a45ca35567bc31b18 3) Click "raw" Note that the result is served with: $ curl -vs "https://gist.githubusercontent.com/arantius/f6fd80b1efad368a45ca35567bc31b18/raw/107eb46664238549969e67b7a22d747cc7517f78/red-border.user.js" 2>&1 | grep -i 'content.security' < Content-Security-Policy: default-src 'none'; style-src 'unsafe-inline'; sandbox Actual results: In Firefox 56 ( Built from https://hg.mozilla.org/releases/mozilla-release/rev/8fbf05f4b92125e081984f5e39b559b83e5cc729 ) and 57 nightly ( Built from https://hg.mozilla.org/mozilla-central/rev/a29052590fc6538b89641e690d11731ca8e78120 ) I navigated to the text source of the JS file, the content script did not run, so my extension feature was not available. Expected results: In Firefox 54 ( Built from https://hg.mozilla.org/releases/mozilla-release/rev/90f18f9c15f7c71c755e387cfc193974fcf8b29c ) AND 55.0.3 ( Built from https://hg.mozilla.org/releases/mozilla-release/rev/10a244c0f835d286d49a571dab59b698d7404e28 ): Greasemonkey's registered content script ( https://github.com/greasemonkey/greasemonkey/blob/b27e7aed4f3ca2822a3ba67d59dbda5fcd048d71/manifest.json#L46 ) ran, and the user script installation dialog was shown. This should work for all, especially current, versions of Firefox.
Attached file repro. extension
Attached file repro. http server
Install attached extension (possibly unpacked). Run attached python server. Navigate to http://localhost/open.user.js and see alert Navigate to http://localhost/closed.user.js and see no alert
CSP does not apply
Summary: REGRESSION: Page CSP blocks extension content script → CSP 'sandbox' directive prevents content scripts from matching, due to unique origin
FYI this also breaks `tabs.executeScript()` on such tabs, but from the update it sounds like the same fix should fix both.
Component: Untriaged → DOM: Security
Product: Firefox → Core
Status: UNCONFIRMED → NEW
Component: DOM: Security → WebExtensions: Request Handling
Ever confirmed: true
Product: Core → Toolkit
We're seeing the same issue with Stylus. It won't style raw gist pages: > it doesn't load any content scripts on raw gist page and if I try to inject CSS manually via `browser.tabs.insertCSS` it says "Error: Missing host permission for the tab", which is absurd since Stylus has `<all_urls>` permission. Ref: https://github.com/StylishThemes/GitHub-Dark/issues/550#issuecomment-339426189
Priority: -- → P2
@andym Why is this marked as wontfix for Fx57? 57 will be the first release with WebExtensions-only support, and this is preventing a very popular extension from behaving properly.
Firefox 57 was merged onto beta several months ago as per the calendar schedule here: https://wiki.mozilla.org/RapidRelease/Calendar
Many Problems with this CSP thing! Crazy example: We can't style AMO pages too ... Please provide a general and easy way to authorize an user to toggle and fine tuning CSP. Firefox 57 break to many things and don't give to us any choice. Now i use Waterfox (and keep an eye on my poor Firefox)
(In reply to decembre56 from comment #10) > We can't style AMO pages too ... That has nothing to do with CSP but a deliberate restriction on AMO pages to prevent access to certain APIs. This is documented here: https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Content_scripts. Please note Chrome has a similar restriction, where you cant run content scripts in Chrome on the Chrome store either.
Am I correct in assuming we can't add any scripts now at all from github on the newest version of Greasemonkey? Nor create a local script anymore? I can imagine users would only want to upload scripts to github, not userstyles.org or others.
(In reply to sten from comment #12) > Am I correct in assuming we can't add any scripts now at all from github on > the newest version of Greasemonkey? That is correct. The only way right now would be to go to `about:config` and *temporarily* disable `security.csp.enable`. So set it to false, then refresh the script on GitHub, install the script, and then set `security.csp.enable` back to `true` (do *not* leave it disabled just for this). As for creating local scripts, there does not seem to be a functionality yet to create blank scripts in GM4.
(In reply to Patrick Westerhoff from comment #13) Thanks for the response. Apparently tampermonkey is able to pop up an installation dialog for github hosted scripts. I don't know about the inner workings of either add-on, but maybe they have a workaround for this bug that might be worth looking into.
Greasemonkey picked a "content script" as a way to detect installation, because it is straightforward and easy to implement. Without knowing that this bug exists. There's plenty of ways to trigger script installation, I just got unlucky.
Blocks: 1334174
Flags: needinfo?(amckay)
Flags: needinfo?(amckay)
Confirming issue on FF 58.0.2 and disappointment at the progress made into fixing it.
Confirming issue still present in Firefox 59.0 (In reply to Patrick Westerhoff from comment #13) >`security.csp.enable`. So set it to false, then refresh the script on GitHub, install the script, and then set >`security.csp.enable` back to `true` (do *not* leave it disabled just for this). I've tried this, but as soon as `security.csp.enable` is back to `true` the issue reappears.
(In reply to Jet from comment #18) > I've tried this, but as soon as `security.csp.enable` is back to `true` the > issue reappears. Yes, because this issue is not fixed. Turning off CSP will allow you to install scripts. After installing them, you should turn CSP back on. Of course, turning it on again will prevent you from installing scripts again. – My point was that you should not leave CSP disabled just for the convenience of being able to install scripts.
Product: Toolkit → WebExtensions
I'm having this issue in my extension that inject STYLE (not even <SCRIPT>) into a website after the user save an URL from which loading the CSS source.
Any plan to fix this, or at least a work-around? It's obviously causing severe issues with NoScript as well, see https://forums.informaction.com/viewtopic.php?f=7&t=24994
(In reply to Giorgio Maone [:mao] from comment #23) > Any plan to fix this, or at least a work-around? > It's obviously causing severe issues with NoScript as well, see > https://forums.informaction.com/viewtopic.php?f=7&t=24994 Hmm this looks serious. So does this mean that those pages aren't rendered at all (and hence no html is displayed, no Javascript is executed), unless they're whitelisted on Noscript? That would be an awful instrument for malicious sites to force users to whitelist their site in Noscript. Or, worse, is Javascript still executed in the background but the page just isn't displayed?
(In reply to swleefers from comment #24) > (In reply to Giorgio Maone [:mao] from comment #23) > > Any plan to fix this, or at least a work-around? > > It's obviously causing severe issues with NoScript as well, see > > https://forums.informaction.com/viewtopic.php?f=7&t=24994 > > Hmm this looks serious. It's mostly a serious usability issue: JavaScript is blocked as expected, but both the popup UI and the placeholders for blocked objects won't work. You cannot know which script sources are blocked on that page, and you can only change permissions (blindly) from the Options page. There's also a security expectation problem users who block WebGL in the TRUSTED preset or in a CUSTOM setting, because WebGL blocking depends on content scripts.
That's worrying indeed. Might other add-ons that block things be affected by this issue as well, such as Ublock or Umatrix?
Firefox screenshots also does not work!
(In reply to kernp25 from comment #27) > Firefox screenshots also does not work! It works fine here with 60.x and 61.x and 62.0b5 all (64-bit) on Windows 10 1709, What OS are you using? Have you fiddled with about:config disabling something screenshots requires?
Flags: needinfo?(kernp25)
(In reply to Jet from comment #28) > (In reply to kernp25 from comment #27) > > Firefox screenshots also does not work! > > > It works fine here with 60.x and 61.x and 62.0b5 all (64-bit) on Windows 10 > 1709, > Are you sure you're talking in the context of this bug? Anything that relies on content scripts, including Mozilla's internal add-ons which more and more Firefox features are based on like Screenshots, are broken by this: 1. Open https://www.dropbox.com/help/security/enable-two-step-verification 2. Try to take a screenshot from the Page Actions menu (the drop-down from the navigation bar) 3. Watch the notification "Whoa! Firefox Screenshots went haywire." Reproducible on both Firefox 61, 62.0b5 and Nightly 63.0a1 (2018-07-05).
Blocks: 1449052, 1451526
Flags: needinfo?(kernp25)
OS: Unspecified → All
Hardware: Unspecified → All
Summary: CSP 'sandbox' directive prevents content scripts from matching, due to unique origin → CSP 'sandbox' directive prevents content scripts from matching, due to unique origin, breaking also browser features [Screenshots]
Version: 56 Branch → Trunk
No longer blocks: 1449052
No longer blocks: 1451526
I'm putting this in the General component (i.e. not webRequest/webNavigation) because this bug is about content scripts, not webRequest. Web pages that use frames with the sandbox attribute suffer from the same issue.
Component: Request Handling → General
See Also: → 1475831
Priority: P2 → P3

(In reply to Giorgio Maone [:mao] from comment #29)

(In reply to Jet from comment #28)

(In reply to kernp25 from comment #27)

Firefox screenshots also does not work!

It works fine here with 60.x and 61.x and 62.0b5 all (64-bit) on Windows 10
1709,

Are you sure you're talking in the context of this bug?
Anything that relies on content scripts, including Mozilla's internal
add-ons which more and more Firefox features are based on like Screenshots,
are broken by this:

  1. Open https://www.dropbox.com/help/security/enable-two-step-verification
  2. Try to take a screenshot from the Page Actions menu (the drop-down from
    the navigation bar)
  3. Watch the notification "Whoa! Firefox Screenshots went haywire."

Reproducible on both Firefox 61, 62.0b5 and Nightly 63.0a1 (2018-07-05).

I've just tried this, going through exactly the steps you have provided. On Firefox 67.0.4 (64-bit), Windows 10, taking a screenshot of that page works for me (clicking on the three dots inside the address bar to get the option "Take a screenshot"). Has anything been fixed in Firefox? Or has the Dropbox page dropped its CSP or anything?

Whiteboard: webext?
Flags: needinfo?(mixedpuppy)

Test file illustrating inability to inject into sandboxed page

Assignee: nobody → mixedpuppy
Blocks: 1267027
Flags: needinfo?(mixedpuppy)
Flags: needinfo?(rob)
Priority: P3 → P2
Whiteboard: webext?
Assignee: mixedpuppy → rob

I looked into this a little bit. The reason why we fail to apply the content-script to pages with a sandbox CSP directive is simple. Such pages get a null principal. In MozDocumentMatcher::Matches we allow about:blank to match with a null-principal. (And also seemingly for data: URIs, which is not documented!)
But because this isn't the case here we are rejecting the principal in WebExtensionPolicy::IsRestrictedDoc.

I found this test page for testing CSP sandboxing.

Detailed manual test case to explore more conditions (source code of page hosted at https://robwu.nl/s/content-script-sandbox/ + extension to test with):

  • same-origin iframe
  • cross-origin iframe
  • srcdoc iframe
  • data:-URL iframe.

With the following combinations:

  • sandbox="" (=unique origin).
  • sandbox="allow-scripts" (just to confirm that injection didn't fail due to scripts being blocked)
    (for blob:-URLs I also added sandbox="allow-same-origin" variants to )
  • No sandbox (=origin of the page).

Firefox 78's current behavior is to only run content scripts in:

  • http(s), but only if not sandboxed.
  • srcdoc frames, but only if not sandboxed.
  • same-origin blob:-URLs.
  • (no content scripts in data:-URLs - bug 1475831)
  • (no content scripts in sandboxed pages - this bug (bug 1475831))

Chromium 86.0.4215.0's current behavior is:

Flags: needinfo?(rob)

Also, I would like to highlight the issue reported in Bug 1517017.

For iframes with sandbox="" in a moz-extension:// page with sandbox="", hosting cross-origin http/https URLs:

  • Firefox 78 - Content scripts do NOT run. BUT changing sandbox to "allow-same-origin" allows content scripts to run.
  • Chrome 86 - Content scripts do run.

Following discussion with Chrome (in crbug 55084, linked from bug 1475831#c16), the future injection behavior in Chrome is as follows:

In Firefox, we will follow the same behavior. This means that bug 1475831 should be fixed by implementing match_origin_as_fallback, and this bug should be fixed by considering the URL of the document when the origin is opaque (i.e. use document's http(s) URL when document principal is null principal). In case the document's URL does not represent the origin (e.g. about:, data:, ... opposed to http(s)), we would have to somehow determine the non-null origin that was responsible for creating the document. That will probably be handled in bug 1475831 (and if not, we should file a follow-up bug to support content scripts in sandboxed frames where the origin cannot be derived from the document's URL).

(In reply to Rob Wu [:robwu] from comment #43)

In case the document's URL does not represent the origin (e.g. about:, data:, ... opposed to http(s)), we would have to somehow determine the non-null origin that was responsible for creating the document. That will probably be handled in bug 1475831 (and if not, we should file a follow-up bug to support content scripts in sandboxed frames where the origin cannot be derived from the document's URL).

bug 1715167 introduces principal.precursorPrincipal that offers this information - https://searchfox.org/mozilla-central/rev/c12a59323ee46b29b90c9917a3a7a70ea714ffec/caps/nsIPrincipal.idl#550-563

Depends on: 1715167

Something must have changed recently, because raw.githubusercontent.com pages are now themed properly.

Still an issue for extensions. Problematic for many NoScript features.

Severity: normal → S3

This is not just an issue with tabs.executeScripts and content_scripts / contentScripts.register / userScripts.register,
but also an issue with the scripting.executeScript (and scripting.registerContentScripts) API.

Blocks: 1687764, 1735474
Whiteboard: [addons-jira]
Blocks: 1739643

I looked at this and finding something that works around this issue isn't hard, but the hard part is deciding when to do the unwrapping so that everything stays reasonable secure.

One approach would be handling this in DocInfo::Principal like this:

@@ -1035,7 +1046,14 @@ nsIPrincipal* DocInfo::Principal() const
         return aLoadInfo->TriggeringPrincipal();
       }
     };
-    mPrincipal.emplace(mObj.match(Matcher(*this)));
+
+    nsCOMPtr<nsIPrincipal> principal = mObj.match(Matcher(*this));
+    if (principal && !URL().InheritsPrincipal() && principal->GetIsNullPrincipal()) {
+      if (nsCOMPtr<nsIPrincipal> precursor = principal->GetPrecursorPrincipal()) {
+        principal = precursor;
+      }
+    }
+    mPrincipal.emplace(principal);
   }
   return

The function doesn't even have that many callers, with WebExtensionPolicy::IsRestrictedDoc being the important one that currently just denies any non content principals. For a more targeted fix we could also use the precursor principal there. Notably as well is that DocInfo::PrincipalURL would fallback to the document URL for non content principals in that scenario.

See Also: → 1853409
See Also: → 1853411
Blocks: 1475831

Not a solution, but at least a workaround: Enable toolkit.legacyUserProfileCustomizations.stylesheets in About:Config, and create the file "Chrome\userContent.css" to the FF profile's root dir, with the following contents:

@-moz-document domain("gist.githubusercontent.com") {
  body {
      color-scheme: dark !important;
  }
}

While users can implement this workaround manually, maybe it would also be possible to create a new user pref that enforces that styling natively, so users don't have to enable legacy stylesheets if they don't otherwise want to.

A user just reported this issue for one of my extensions (it injects a script that adds a UI to draw the target WebP image on a canvas and save to a different format):

What surprised me was that sandbox blocked scripts in the stand-alone image viewer (example: https://www.jeffersonscher.com/res/img-with-csp.php?csp=sandbox - you can test with right-clicking a background area > Take Screenshot).

This is inconsistent with the result for

Content-Security-Policy: script-src: 'none';

which does not prevent content scripts from running on the same pages (example: https://www.jeffersonscher.com/res/img-with-csp.php?csp=noscript - Take Screenshot works)

In the context of the stand-alone image viewer, there is no obvious security benefit to disallowing extension content scripts. It appears only to frustrate user wishes to use extensions to work with the image. But it might not be efficient to handle as a separate bug, so I am commenting here.

ExtensionPolicyService::InjectContentScripts has two code paths, one
with preloading and one without. The most important case, without
preloading (i.e. executing immediately) is covered extensively by unit
tests. The preloading case had zero test coverage before.

Due to existing implementation limitations (*), the actual behavior of
preloading differs logically from the non-preloading case. Before making
any changes to the area, this patch adds documentation (mainly to
DocInfo::PrincipalURL and DocInfo::Principal) and extensive test
coverage to explicitly confirm the correctness of preloading behavior.

(*) in short: with DOMWindow (non-preloading), the principal is always
known and available, whereas with LoadInfo (preloading), the principal
has to be reconstructed, but without enough information available to
tell the difference for null principals.

This patch adds support for matching http(s) (and file:) documents even
if they are sandboxed. Previously, there was no way for extensions to
run content scripts there.

Pushed by rob@robwu.nl: https://hg.mozilla.org/integration/autoland/rev/3f63c4b7f235 Add documentation and test coverage for content script preloading r=rpl https://hg.mozilla.org/integration/autoland/rev/6b3f0c4c2c17 Support content scripts on sandboxed http(s)/file:-URLs r=rpl
Regressions: 1896510
Status: NEW → RESOLVED
Closed: 6 months ago
Resolution: --- → FIXED
Target Milestone: --- → 128 Branch
Keywords: dev-doc-needed
No longer regressions: 1896510

Added a release note in Support for content scripts on sandboxed http(s) and file: URLs #34460. Couldn't see any need for changes on the pattern matching, CSP, or script API pages.

You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: