Open Bug 1392090 Opened 7 years ago Updated 2 years ago

<noscript> html tags are not rendered if the Content-Security-Policy "script-src" is set to 'none'

Categories

(Core :: Security, defect, P3)

57 Branch
defect

Tracking

()

Tracking Status
firefox57 --- wontfix

People

(Reporter: thilo-wolf, Unassigned)

Details

User Agent: Mozilla/5.0 (X11; Linux x86_64; rv:57.0) Gecko/20100101 Firefox/57.0
Build ID: 20170818100226

Steps to reproduce:

1. Install Firefox Nightly version 57
2. Install the addon JavaScript Toggle On and Off (WebExtension) from addons page
3. Open a page that contains Javascript code and at least one <noscript> tag like http://www.enable-javascript.com/
4. Toggle Javascript to be enabled or disabled via addon.


Actual results:

If Javascript is enabled the page shows a box with a green border reading: "Javascript is enabled in your web browser. If you disable JavaScript, this text will change."

If Javascript is disabled the page does not show a box.


Expected results:

If Javascript is disabled a box with a red border is shown:  "Javascript is disabled in your web browser. If you enable JavaScript, this text will change"

In previous versions of Firefox addons could change "about:config" entries. NoScript and other Javascript deactivating addons toggled Javascript to be disabled. This would result in <noscript>-tags to be rendered.

The new approach via  'Content-Security-Policy' and  'script-src' 'none' does not work that way: <noscript>-tags will only be shown if Javascript is disabled in "about:config".
Component: Untriaged → WebExtensions: General
Product: Firefox → Toolkit
Status: UNCONFIRMED → RESOLVED
Closed: 7 years ago
Resolution: --- → DUPLICATE
I am sorry, but this is not a duplicate of 1363859.
The problem is not that WebExtensions cannot change the about:config setting to disable Javascript globally.
The problem is that <noscript> html tags are not rendered if the Content-Security-Policy "script-src" is set to 'none'.
Status: RESOLVED → UNCONFIRMED
Resolution: DUPLICATE → ---
In that case, this bug has nothing to do with WebExtensions.
Component: WebExtensions: General → DOM
Product: Toolkit → Core
Summary: WebExtension API behaviour for NoScript differs from behaviour of pre-57 version → <noscript> html tags are not rendered if the Content-Security-Policy "script-src" is set to 'none'
I can reproduce this on OSX as well following STR in comment 0.
Component: DOM → Layout
Priority: -- → P3
So, this impacts uMatrix and uBlock which both use CSPs for JS filtering.

I was experimenting with switching to uMatrix since bug #1214733 has been languishing for quite some time and the day of doom approaches for legacy extensions.

But, whether I block JS in whitelist in uMatrix (* set to red and individual sites to green) or blacklist, content in <noscript> tags are not rendered, so fallbacks fail.

https://m8y.org/tmp/testcase457.xhtml  (A trivial testcase)

https://discourse.mozilla.org/t/support-umatrix/5131?page=2  (an ironic link I found trying to get uMatrix support on this subject - Mozilla switched to discourse [ugh] which pays a bare passing respect to progressive enhancement using <noscript> https://kryogenix.org/code/browser/everyonehasjs.html people!)


Here's some bugs in uMatrix and uBlock which encountered this.

https://github.com/gorhill/uMatrix/issues/319   (locked to contributors by uMatrix dev who rejected idea of flagging docshells where JS was set, for some reason)

https://github.com/chrisaljoudi/uBlock/issues/574   (uBlock bug - bz replied to this one pointing out the feasibility of the JS flag solution - the CSS thing of course would not work since browsers do not parse content of <noscript> blocks when JS is enabled)
Oh, and IMO it isn't just 'none' that is the problem, it is any time the domain of the docshell matches the CSP block.
If I'm blocking m8y.org with CSP and my tab is m8y.org, any HTML from m8y.org should parse <noscript> it seems to me...
> locked to contributors by uMatrix dev who rejected idea of flagging docshells where JS was set, for some reason

The issue was locked because noise added by people just throwing in there guessed solutions instead of actually contributing by providing real actual working solutions with a thorough understanding of the issue at hand.

> rejected idea of flagging docshells where JS was set

I have no clue what you are talking about. Nowhere can I find "flag" and neither "docshell" in there.

> uBlock bug - bz replied

He replied on the issue tracker of abandonware "uBlock" which hasn't seen development in years. I have asked for clarification regarding "setting allowJavascript on a docshell". I am not aware of any WebExtensions API related to this.
First of all, all the bits about uMatrix or uBlock in this bug are unrelated to the actual issue reported here.  I will follow up on those in the relevant bug trackers.

For the bug reported here...  The problem is that noscript needs parser support, but it's possible for CSP to set script-src to "none" _after_ the noscript has been parsed.

That said, if we do discover the CSP "early enough" we could try to communicate that to the parser.  Henri, does that seem feasible?
Component: Layout → Security
Flags: needinfo?(hsivonen)
Oh, and as for comment 6...  Just because the HTML is from m8y.org doesn't mean the _scripts_ will be, and they could be from a host that is not blocked by CSP.  So it's really hard to make any sense of noscript for values of script-src other than 'none'
Oh, I see.  uBlock Origin actually injects a CSP.  In that case, fixing this bug would in fact help there.
Status: UNCONFIRMED → NEW
Ever confirmed: true
(In reply to Boris Zbarsky [:bz] (no decent commit message means r-) from comment #8)
> That said, if we do discover the CSP "early enough" we could try to
> communicate that to the parser.  Henri, does that seem feasible?

If "early enough" means in HTTP headers, yes. If early <meta>, probably no. (Or too messy to bother.) In general, I'm not too happy about <meta> support for CSP. 

The code of interest is at:
https://searchfox.org/mozilla-central/source/parser/html/nsHtml5StreamParser.cpp#911

Do WebExtensions synthesize HTTP header-like CSP or do they inject <meta> somehow?

What does the CSP and HTML specs say about this?
Flags: needinfo?(hsivonen)
> What does the CSP and HTML specs say about this?

The HTML spec relies on https://html.spec.whatwg.org/multipage/webappapis.html#concept-bc-script which does NOT include CSP in the list of things that can disable scripting, effectively.  But it does include sandboxing.

I filed https://github.com/whatwg/html/issues/3230
So, bz's point about CSP set to domain of tab which includes other scripts is well taken.  Personally on sites where I do progressive enhancement w/ script detection, what I care about is blocking the site.  If that's blocked, most everything else is going to be problematic.

I was curious what NoScript does, since it has been working wonderfully for me for a very long time, so I made:
https://m8y.org/tmp/testcase457b.xhtml

This one is same as the other testcase, but there's a script link to jquery on the google apis domain.  If I block m8y.org in NoScript, but allow ajax.googleapis.com, the <noscript> on m8y.org is still parsed, which is fine by me both as a dev and NoScript user ☺

Dunno if it makes sense to have the browser determine this tho, and making web exteions use that javascript toggle flag that bz mentioned prior is maybe a better idea.   Do they have access to it?
So. This is exciting.  Maone's WebExtension NoScript correctly handles http://m8y.org/tmp/testcase457.xhtml
In stable even!

uMatrix does not.  Presumably due to this CSP thing.
But. It does mean that there is another way to get this working, and Maone is using it ♥
Eh, sorry, false alarm.  His behaviour is perfect - noscript tags get parsed if the website that owns the document containing them gets whitelisted.  But he's doing it the hackish innerHTML way - basically doing the browser's work for it.

So. Good for Maone, but it means this bug, and bug 1367161 are still legit.

IMO fixing this one to work the way NoScript WebExtension works would be cleaner since uMatrix/uBlock would "just work" with no additional changes needed...
(In reply to Boris Zbarsky [:bz] (no decent commit message means r-) from comment #12)
> > What does the CSP and HTML specs say about this?
> 
> The HTML spec relies on
> https://html.spec.whatwg.org/multipage/webappapis.html#concept-bc-script
> which does NOT include CSP in the list of things that can disable scripting,
> effectively.  But it does include sandboxing.
> 
> I filed https://github.com/whatwg/html/issues/3230

If sandboxing is supposed to work, has anyone tried setting the CSP sandbox attribute[0] instead of script-src: none?
Bug 1417494 indicates that sandbox should apply <noscript> in iframes, but it says nothing about sandboxing applied to the top level document.


[0] https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/sandbox
After some testing it appears that injecting |Content-Security-Policy: sandbox;| or any variation thereof that does not set allow-scripts has the desired effect on Nightly (FF59) at least. On dev edition (58) it renders the noscript tag incorrectly for me.
BTW, mild followup to comment #14 - uMatrix now works around this FF behaviour WRT <noscript> in a similar fashion to NoScript webextension with:
☑  Spoof <noscript> tags when 1st-party scripts are blocked 

In preferences.
So: http://m8y.org/tmp/testcase457b.xhtml  Now renders in both if m8y.org is blocked, regardless of whether the google JS is whitelisted, which would be the traditional NoScript and IMO most logical <noscript> behaviour.

The only downside is uMatrix doesn't seem to render the CSS, which renders fine in NoScript.  They may be trying to be more paranoid and filtering the style tag?
> They may be trying to be more paranoid and filtering the style tag?

"They" is me.

Your page is served as a XML document, and as per spec[1]:

> The noscript element is only effective in the HTML syntax, it has no effect in the XML syntax. This is because the way it works is by essentially "turning off" the parser when scripts are enabled, so that the contents of the element are treated as pure text and not as real elements. XML does not define a mechanism by which to do this.

uMatrix uses noscript.textContent through a DOMParser to force noscript tags to be rendered. However, the noscript tags are rendered when embedded in an XML document, and in such case noscript.textContent no longer contains the un-parsed code, as would be expected if these noscript tags were embedded in a HTML document.

NoScript uses noscript.innerHTML, but its use is discouraged as per AMO rules[2].

***

[1] https://html.spec.whatwg.org/multipage/scripting.html#the-noscript-element
[2] https://github.com/mdn/webextensions-examples/issues/115
huh. that's fascinating, since w/ JS disabled firefox will happily parse any random stuff in "XHTML5" which w3c seems to pretty much define as html5 plus strict parsing which is pretty much the only reason I serve it that way (to catch my own carelessness).

But. good to know your method usually works. Thanks.

Also good to know FF is so strict about this, since it allowed things like importing entire DOM from xhtml into html to apply print styling like years before chrome ended up allowing that.

And, yes, I realise xhtml is dead, apart from responseXML, XSLT, certain primitive parsers or just as a cheap form of strictness for relics.
Oh. I might as well bring this up here... I found out that twitter <noscript> blocks are still broken in NoScript.
https://t.co/IkQfSDALAn
is a redirector that generates the following dubious HTML:
<head><meta name="referrer" content="always"><noscript><META http-equiv="refresh" content="0;URL=http://marginalrevolution.com/marginalrevolution/2018/01/get-jail-free-cards.html"></noscript><title>http://marginalrevolution.com/marginalrevolution/2018/01/get-jail-free-cards.html</title></head><script>window.opener = null; location.replace("http:\/\/marginalrevolution.com\/marginalrevolution\/2018\/01\/get-jail-free-cards.html")</script>

Why they do this, I have no idea.  I mean seriously, why bother. either the meta works or it doesn't.

Sorry for the arbitrary nature of link, I don't use twitter often, and this was top tweet on my friend's feed, I have no idea how to generate another one.   Just figured I'd mention it as a prominent place the hack fails.

Twitter in general does some fairly insane stuff with JS blocked - blocking JS + cookies will sometimes-but-not-always put twitter into infinite redirections.
Severity: normal → S3
You need to log in before you can comment on or make changes to this bug.