CSP: Add warning if <meta> CSP is ignored for whatever reason

UNCONFIRMED
Unassigned

Status

()

P3
normal
UNCONFIRMED
2 years ago
2 years ago

People

(Reporter: galt, Unassigned)

Tracking

53 Branch
Points:
---

Firefox Tracking Flags

(Not tracked)

Details

(Whiteboard: [domsecurity-backlog1])

(Reporter)

Description

2 years ago
User Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:53.0) Gecko/20100101 Firefox/53.0
Build ID: 20170504105526

Steps to reproduce:

I have a CGI that was accidentally outputting a short second HTTP response header.



Actual results:

Firefox completely failed to enforce the CSP policy in the meta tag,
despite a browser console message saying that a nonce was found.
Thus it made the CGI vulnerable to XSS hacking in Firefox.


Expected results:

Since an accidental duplicate header is an easy mistake to make in a CGI,
it is really sad that such a little thing can entirely foil the CSP protections
in FF.  FYI Chrome and Safari do not fail to enforce CSP and XSS
in this situation.
You can see a simple test here:
Duplicate header destroys CSP enforcement:
http://hgwdev.cse.ucsc.edu/~galt/FF-CSP-DuplicateHeader.html

Without duplicate http header, CSP enforcement works.
http://hgwdev.cse.ucsc.edu/~galt/FF-CSP-NO-DuplicateHeader.html

The URLs above are to static html files rather than being directly
output by a CGI. But they still fail.

Comment 1

2 years ago
In http://hgwdev.cse.ucsc.edu/~galt/FF-CSP-DuplicateHeader.html, the page content "Content-type:text/html" triggers opening <body> and so all the contents of the page go into <body>, including the CSP meta tag.

My understanding (which could be wrong) is that the end of headers is signalled by a repeated \r\n (CRLF), and so really the problem you're seeing isn't a 'double header', it's a premature ending of the header part of the http response message, and the presence of 'garbage' at the start of the HTTP response then triggers HTML parsing at the 'wrong' time.

(In reply to Galt Barber from comment #0)
>  FYI Chrome and Safari do not fail to enforce CSP and XSS
> in this situation.
> You can see a simple test here:
> Duplicate header destroys CSP enforcement:
> http://hgwdev.cse.ucsc.edu/~galt/FF-CSP-DuplicateHeader.html

If I load that page in Chrome I still get an 'XSS' javascript alert. Same thing in Safari. They both produce similar DOM to Firefox. Chrome even puts this in its developer tools:

The Content Security Policy 'default-src *; script-src 'self' 'unsafe-inline' 'nonce-avSEJABGPnYQBgLT1nOjvrheqrMa'; style-src * 'unsafe-inline'; font-src * data:; img-src * data:;' was delivered via a <meta> element outside the document's <head>, which is disallowed. The policy has been ignored.

... which seems pretty unequivocal. Are your sure this page accurately represents the issue you were seeing earlier?
Flags: needinfo?(galt)
Summary: Duplicate HTTP response header ruins CSP enforcement → Duplicate HTTP response header breaks CSP enforcement of CSP <meta> tag
(Reporter)

Comment 2

2 years ago
Yes, the extra header from the CGI is just a duplicate
where one part of the library which has already output
an http header calls some other code that does the same thing.

Here is the output coming directly from the CGI without Apache getting involved:

/usr/local/apache/cgi-bin-galt/hgc 'hgsid=391450725_c7MZiIuHaABjNXQMPIWki2qIaxes&c=chrIV%3Cscript%3Ealert(String.fromCharCode(88,83,83))%3C%2fscript%3E&l=8536499&r=8536942&o=8536499&t=8536942&g=axtNetCb1&i=axtNetCb1&db='
Set-Cookie: hguid=13217555_iSmuAoBLMeJVXGiTJZX2eKixLszz; path=/; domain=.ucsc.edu; expires=Thu, 31-Dec-2037 23:59:59 GMT
Content-Type:text/html


Content-type:text/html

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<HTML>
<HEAD>
[...]
-------------

So any stray text (in this case the duplicate content-type header) 
that appears before the actual page starts is immediately treated as body.
Then the real <head> and doctype must be ignored.
Then it is ignoring the doctype, header, and everything else.

What alarms me is just that it is an easy mistake and it completely disables 
the CSP protections. Firefox offered no warning about the CSP being ignored.

In our case, the code in question that accidentally creates the duplicate http 
response headers is from an error page that is normally almost never seen 
by users and testers, but which XSS hackers would quickly find.

I am all for CGIs producing correct output.
Yes, programmers and testers should take responsibility 
for getting it right and fixing it. I have done just that in our own code.

I think it would be better in some ways for the browser to complain
with a hard error if it sees some stray text preceding an otherwise
normal html page.  Then the CSP would not get ignored and fail to 
protect users.

You might have an old version of Chrome. On mine, Chrome says a warning
that it has stopped the bad page from running. No XSS popup appears.

Thanks for taking the time to investigate this.
Flags: needinfo?(galt)

Comment 3

2 years ago
(In reply to Galt Barber from comment #2)
> You might have an old version of Chrome. On mine, Chrome says a warning
> that it has stopped the bad page from running. No XSS popup appears.

Version 58.0.3029.110 (64-bit) on OS X. I'd be curious where the Chrome message you're talking about comes from - maybe an add-on you're running?

(In reply to Galt Barber from comment #2)
> I think it would be better in some ways for the browser to complain
> with a hard error if it sees some stray text preceding an otherwise
> normal html page.  Then the CSP would not get ignored and fail to 
> protect users.

But the website would also break completely. That's the problem - doing what you suggest would break unsuspecting websites.

Christoph, any chance we could just not ignore the CSP even if it's outside <head> ? I presume it's been specced this way, or something? I don't have background on why. Other than that, I don't know what we could do to improve things here, so I'm tempted to open up and mark invalid/wontfix.
Flags: needinfo?(ckerschb)
(Reporter)

Comment 4

2 years ago
FYI Chrome has added new anti-XSS protections. It is not some add-on.
It steps right in and says that it will not
allow the page to run. It does not show you anything of the page returned - it only
shows a big warning message about how the page is behaving badly and it looks like
a hacking attempt, so to protect you and your identity etc it is is not allowing it.
It does provide only one link which points to the website base without any url parameters
that says maybe you want to visit the main site.
(Reporter)

Comment 5

2 years ago
I see that the browser will tolerate multiple blank links before the
html page really starts. But if you put in a single non-blank character like X it will
ignore the html header and CSP protections.

X
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<HTML>
<HEAD>

<meta http-equiv='Content-Security-Policy' content="default-src *; script-src 'self' 'unsafe-inline' 'nonce-avSEJABGPnYQBgLT1nOjvrheqrMa'; style-src * 'unsafe-inline'; font-src * data:; img-src * data:;">
        
<META HTTP-EQUIV="Content-Type" CONTENT="text/html;CHARSET=iso-8859-1">
<META http-equiv="Content-Script-Type" content="text/javascript">
<META HTTP-EQUIV="Pragma" CONTENT="no-cache">
<META HTTP-EQUIV="Expires" CONTENT="-1">
<TITLE>CGI variable error</TITLE>
</HEAD>
<BODY>
(Reporter)

Comment 6

2 years ago
You were saying that you thought that because it sees text
and immediately starts into it as if it were inside of a missing <BODY> tag,
it therefore ignores the HEAD, including the CSP.

However, I see that the title tag embedded in the HEAD section is still working.
My guess is that many things inside the HEAD section still work.

Anyway, for security's sake, it would be better to stop if the page has
stray text before a CSP statement rather than allowing a hacker's js to run.
The user will not get hacked, the developer will quickly fix their bug
when they discover the issue.
(In reply to :Gijs from comment #3)
> Christoph, any chance we could just not ignore the CSP even if it's outside
> <head> ? I presume it's been specced this way, or something? I don't have
> background on why. Other than that, I don't know what we could do to improve
> things here, so I'm tempted to open up and mark invalid/wontfix.

Yeah, strictly speaking this is a WONTFIX, the spec mentions that meta-csp needs to placed inside the <head> and should otherwise be ignored [1]. Anyhow, I agree that logging a warning to the console might be helpful in that case so that webdevs know that the meta-csp has been ignored, or at least something is wrong with their setup instead of silently ignoring the meta-csp. I don't know if that is easily feasible though, given the description in comment 1.

[1] https://www.w3.org/TR/CSP2/#delivery-html-meta-element
Flags: needinfo?(ckerschb)

Comment 8

2 years ago
(In reply to Galt Barber from comment #4)
> FYI Chrome has added new anti-XSS protections. It is not some add-on.
> It steps right in and says that it will not
> allow the page to run. It does not show you anything of the page returned -
> it only
> shows a big warning message about how the page is behaving badly and it
> looks like
> a hacking attempt, so to protect you and your identity etc it is is not
> allowing it.

So why am I not seeing the same thing? What version of Chrome are you running? Are you seeing this with the test links from comment #0 or with the 'real' page which had this issue? Is there documentation for these "new anti-XSS protections"? The only recent thing (you said "new", so I assume you don't mean the stuff dating to 2012) I can find is https://stackoverflow.com/questions/43249998/chrome-err-blocked-by-xss-auditor-details which suggests it's blocking legitimate usecases. :-\

(In reply to Christoph Kerschbaumer [:ckerschb] from comment #7)
> (In reply to :Gijs from comment #3)
> > Christoph, any chance we could just not ignore the CSP even if it's outside
> > <head> ? I presume it's been specced this way, or something? I don't have
> > background on why. Other than that, I don't know what we could do to improve
> > things here, so I'm tempted to open up and mark invalid/wontfix.
> 
> Yeah, strictly speaking this is a WONTFIX, the spec mentions that meta-csp
> needs to placed inside the <head> and should otherwise be ignored [1].
> Anyhow, I agree that logging a warning to the console might be helpful in
> that case so that webdevs know that the meta-csp has been ignored, or at
> least something is wrong with their setup instead of silently ignoring the
> meta-csp. I don't know if that is easily feasible though, given the
> description in comment 1.
> 
> [1] https://www.w3.org/TR/CSP2/#delivery-html-meta-element

We can add a warning in the web console but that doesn't address the concern in comment #0, in that users would still be 'vulnerable'. Of course, CSP is only meant to be defense-in-depth, not a way of abdicating responsibility on doing proper input sanitization etc...


Galt: I suspect the best fix for your site is to move your CSP stuff into headers instead of a <meta> tag.

Given comment #7 "strictly speaking this is WONTFIX", I'm going to at least unhide this bug.
Group: firefox-core-security
Component: Untriaged → DOM: Security
Product: Firefox → Core
Summary: Duplicate HTTP response header breaks CSP enforcement of CSP <meta> tag → CSP <meta> tag that ends up in <body> because of broken cgi scripts is ignored without warnings/errors

Comment 9

2 years ago
(In reply to Galt Barber from comment #6)
> You were saying that you thought that because it sees text
> and immediately starts into it as if it were inside of a missing <BODY> tag,
> it therefore ignores the HEAD, including the CSP.
> 
> However, I see that the title tag embedded in the HEAD section is still
> working.
> My guess is that many things inside the HEAD section still work.

Yes, <title> works in <body>, see e.g. data:text/html,<body><title>Hello</title>

This is specced: https://html.spec.whatwg.org/multipage/dom.html#the-title-element-2

> The title element of a document is the first title element in the document (in tree order), if there is one, or null otherwise.

which doesn't specify that it needs to be in <head> in order for it to be used.

On the other hand, as Christoph already noted, CSP2 requires the <meta> element is in the head. On the other hand, https://w3c.github.io/webappsec-csp/#intro and https://www.w3.org/TR/CSP/#meta-element don't. Maybe the CSP working group is changing their mind? Or maybe I just can't find the right bit of the spec. Christoph?

Either way, as all versions of the spec note, elements that appear before the CSP do not necessarily abide by the CSP (because of how HTML parsing works) and so the sooner you set the CSP, the better - nothing beats a header in that respect.

> the developer will quickly fix their bug
> when they discover the issue.

Unfortunately, this is not how the internet works. Browsers would love to make all kinds of changes about broken things and can't, because of all the old content that relies on things working the way they Always Have. Backwards compatibility is king. I can guarantee you that changing the HTML parsing element to either allow random gunk to appear before the doctype, or to abort parsing entirely (which in any case would be counter to the spirit of how HTML parsing is set up - to almost never fail entirely) is not a backwards compatible change.
Flags: needinfo?(ckerschb)
(Reporter)

Comment 10

2 years ago
TYPO
>I see that the browser will tolerate multiple blank links before the
>html page really starts. 

Sorry, this was supposed to read:

I see that the browser will tolerate multiple blank LINES before the
html page really starts.
(Reporter)

Comment 11

2 years ago
I find it bizarre that the browser treats text before any legitimate tags
as something so important that it then completely ignores the real tags that follow.
Much better to just abort so that the illegitimate output is identified and fixed
right away. This is for a case where the header clearly states html output.
So the output that appears before any legitimate tag should be either ignored
or produce a failure or strong warning. This is HTML after all.

Well, I would at the very least vote for a strong console warning when
the meta CSP is being ignored on a technicality.

Also, I read somewhere online today that FF at one time used to treat HEAD tags 
that appeared in the BODY by actually sticking them into the header part of the document tree.
In which case they would not be ignored, and CSP protection would be preserved.

If you need any other information from me, please let me know.
I am not a frequent bugzilla user.

Comment 12

2 years ago
1. The current behavior is pretty clearly what we specified: see https://html.spec.whatwg.org/#attr-meta-http-equiv-content-security-policy.

2. I think we created this requirement because folks were concerned about distributing CSP via `<meta>` in the first place, for fear of malicious injection of a policy that would turn off specific scripts on a page. Locking the policy to the document's `<head>` was meant to mitigate that risk. I'm not philosophically opposed to weakening the checks if folks decide that that risk is less important than the risk discussed here. I suspect that pages with injection potential before any content at all have other problems, but I'm very willing to be convinced otherwise. :)
(In reply to :Gijs from comment #9)
> Maybe the CSP working group is changing their mind? Or maybe I just can't find the right bit of the spec. Christoph?

I think Mike already answered your question within comment 12. My take on this is is the following: we shouldn't loosen that requirement and the meta CSP should be placed within the <head>. I am more worried about attackers inject random CSPs using the meta tag VS developers mess up their CSP. In general I think it's better to ship CSP using the header instead of using the meta tag anyway, but that's not up for discussion here :-)
Flags: needinfo?(ckerschb)
(Reporter)

Comment 14

2 years ago
Content security policy state (http-equiv="content-security-policy")
    This pragma enforces a Content Security Policy on a Document. [CSP]
        If the meta element is not a child of a head element, abort these steps.

The thing is, however, my correctly formatted head and meta tags with CSP are getting IGNORED
by the browser. 

Here is the source: (assume correctly formatted http response header for html)
----------
X
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<HTML>
<HEAD>

<meta http-equiv='Content-Security-Policy' content="default-src *; script-src 'self' 'unsafe-inline' 'nonce-avSEJABGPnYQBgLT1nOjvrheqrMa'; style-src * 'unsafe-inline'; font-src * data:; img-src * data:;">
	
<META HTTP-EQUIV="Content-Type" CONTENT="text/html;CHARSET=iso-8859-1">
<META http-equiv="Content-Script-Type" content="text/javascript">
<META HTTP-EQUIV="Pragma" CONTENT="no-cache">
<META HTTP-EQUIV="Expires" CONTENT="-1">
<TITLE>CGI variable error</TITLE>
</HEAD>
<BODY>


hgc: bad input variables c=chrIV<script>alert(String.fromCharCode(88,83,83))</script> l=8536499 r=8536942<!-- HGERROR -->


</BODY></HTML>
-----------

I see a correctly formatted html document with HEAD and META and CSP. 
The only problem is a little stray character at the top makes the browser
do weird things. You could either ignore that leading text before the first tag.
Or you could stash it somewhere and append it to the head of the BODY perhaps later.
That way you would not miss all the other good tags in the page.
And the CSP would be enforced.
(Reporter)

Comment 15

2 years ago
We might consider using header instead of meta in the future,
but it would require too many changes to our somewhat large codebase
to go off and attempt it right now.

One really nice advantage of the meta tag is that you can
see the policy by just doing view source. So checking for
presence and correctness is much easier than for mostly invisible
http header response lines.
After discussing things with Dan we both agree that we should spit out a warning in the console if meta CSP is ignored for whatever reasons. Adding to the backlog for now.
Priority: -- → P3
Summary: CSP <meta> tag that ends up in <body> because of broken cgi scripts is ignored without warnings/errors → CSP: Add warning if <meta> CSP is ignored for whatever reason
Whiteboard: [domsecurity-backlog1]
You need to log in before you can comment on or make changes to this bug.