We have been working hard lately to finish documenting the Content Security Policy proposal, which we plan to start implementing very soon. For those of you who have followed the progression of CSP, you have seen the model grow quite a bit in complexity. As one thinks through the CSP model, it becomes clear that a certain amount of complexity is in fact necessary for the model to be useful. I have done my best to describe the model and provide justification for the various restrictions here: http://people.mozilla.org/~bsterne/content-security-policy/details.html
We now have a specification document to work from (thanks, Sid!) and it and other supporting docs can be found on the Mozilla Wiki: https://wiki.mozilla.org/Security/CSP/Spec
If you have feedback that you would like to share regarding Content Security Policy, please do so ASAP as the window for making changes to the model will soon be closing.
> We now have a specification document to work from (thanks, Sid!) and > it and other supporting docs can be found on the Mozilla Wiki: > https://wiki.mozilla.org/Security/CSP/Spec
The policy does not say explicitly what happens to javascript: hyperlinks and the on* event handlers.
You shouldn't use an X- header because it's going to stick around and preventing standardization (see X-Complaints-To on Usenet).
> You shouldn't use an X- header because it's going to stick around and > preventing standardization (see X-Complaints-To on Usenet).
I think an X-header makes sense for CSP at this point, since it is not yet standardized. A standards group like W3C's public-webapps is probably the right venue for that conversation to take place.
Are we expecting to see some or all of this in Firefox 3.5, or Firefox-next?
On 02/04/09 22:12, Brandon Sterne wrote:
> If you have feedback that you would like to share regarding Content > Security Policy, please do so ASAP as the window for making changes to > the model will soon be closing.
- When might we see the "Refinements" section with the JS/eval changes? Or is that the other document?
- "When both a X-Content-Security-Policy HTTP header and meta tag are present, the intersection of the two policies is enforced; essentially, the browser enforces the most *relaxed* policy satisfying both the policies specified in the meta tag and header."
Surely you mean "strict", not "relaxed"? The example seems to show that the resulting policy is more strict than either of the two source policies.
- What happens if a Report-URI encounters a redirect? We should say specifically in the spec what we do, and I think we should honour it. This would allow us to do "all reports must be sent to the same host that served the protected content" while still allowing people to set it up so that the logging server was a separate machine.
- Would it not be more flexible, with negligible change in implementation complexity, to make report-uri multi-valued? We have to support multiple values anyway.
- "but a declared (unexpanded) policy always has the "allow" directive." I think you need to make it more clear that "allow" is mandatory. But what was the logic behind making it so? Why not assume "allow *", which is what browsers do in the absence of CSP anyway?
- The formal syntax uses "<host-expr-list>" but it's undefined in that formal section. Is that intentional?
- Should there be a space or other separator in the middle of "<allow-directive><directive-list>"?
- The Violation Report Sample has: "<blocked-uri>some_image.png</blocked-uri>". Given that the directive blocked was a "self" directive, I would expect some_image.png to be on another host, and therefore for a full URI to be provided. (This is vital for trying to find out who is behind the content injection.) What have I missed?
- "policy-uri documents must be served with the MIME type text/content-security-policy to be valid" This probably needs an "x-" until we've registered it, which we should do before deployment. It's not a complex process, I hear.
- "Hostname, including an optional leading wildcard, e.g. *.mozilla.org" Does that include foo.bar.baz.mozilla.org? If so, we should say so explicitly (in both docs).
> - "When both a X-Content-Security-Policy HTTP header and meta tag > are present, the intersection of the two policies is enforced; > essentially, the browser enforces the most *relaxed* policy > satisfying both the policies specified in the meta tag and header."
> Surely you mean "strict", not "relaxed"? The example seems to show > that the resulting policy is more strict than either of the two > source policies.
I think "relaxed" is the intent here, within the context of "the most relaxed policy *satisfying both* ... the meta tag and header." So the intersection is more strict than either on its own, but no more strict than that intersection. I agree that the wording is a bit confusing.
Cheers,
J
--- Johnathan Nightingale Human Shield john...@mozilla.com
> I think "relaxed" is the intent here, within the context of "the most > relaxed policy *satisfying both* ... the meta tag and header." So the > intersection is more strict than either on its own, but no more strict > than that intersection. I agree that the wording is a bit confusing.
Yeah, that's correct. I must have been over-caffeinated when I wrote that. Here is the new, hopefully clearer text:
"essentially, the browser enforces a policy that is more strict than both the policies specified in the meta tag and header, but only strict enough to correspond to rules in both policies. Any web request that satisfied both policies alone will be accepted by the new policy, but any request rejected by either one or both of the two policies will be rejected."
> - When might we see the "Refinements" section with the JS/eval changes? > Or is that the other document?
The content is in the other document, but most likely we'll be moving that to the wiki too (I've linked to the description doc in the mean time).
> - What happens if a Report-URI encounters a redirect? We should say > specifically in the spec what we do, and I think we should honour it. > This would allow us to do "all reports must be sent to the same host > that served the protected content" while still allowing people to set it > up so that the logging server was a separate machine.
Personally, I don't like the idea of honoring redirects for logging... if a meta tag can be injected into a page (with a CSP header or not) and the site hosts an open redirect, suddenly cookies can be stolen from all visitors to a site.
> - Would it not be more flexible, with negligible change in > implementation complexity, to make report-uri multi-valued? We have to > support multiple values anyway.
While it's true that this would be easy to implement, I think we need to set a limit. We don't want to spawn off 100 requests every time a policy is violated. If that happens, attackers could leverage the reporting mechanism in CSP to flood a network with traffic. I'm not convinced that widespread use will demand more than two report URIs, and it's not difficult to set up that report URI recipient service to fork copies to multiple other destinations.
> - "but a declared (unexpanded) policy always has the "allow" directive." > I think you need to make it more clear that "allow" is mandatory. But > what was the logic behind making it so? Why not assume "allow *", which > is what browsers do in the absence of CSP anyway?
I think the intention for requiring the allow directive was to force the policy-writer into writing out the default case to minimize possibility for false assumptions. I'm not sure though.
> - The formal syntax uses "<host-expr-list>" but it's undefined in that > formal section. Is that intentional?
Nope... that's a mistake, should be "<source-list>".
> - Should there be a space or other separator in the middle of > "<allow-directive><directive-list>"?
Indeed. ";"
> - The Violation Report Sample has: > "<blocked-uri>some_image.png</blocked-uri>". Given that the directive > blocked was a "self" directive, I would expect some_image.png to be on > another host, and therefore for a full URI to be provided. (This is > vital for trying to find out who is behind the content injection.) What > have I missed?
You're right, a full URI would be appropriate there. The wiki was actually parsing out the http://evil.com/ part from both references to "some_image.png" and omitting it... weird.
Hi, Gerv. Thanks a lot for your comments. I'll address the comments that weren't already covered by Johnathan or Sid, both of whom I agree with.
On Apr 6, 3:56 am, Gervase Markham <g...@mozilla.org> wrote:
> Are we expecting to see some or all of this in Firefox 3.5, or Firefox-next?
Firefox-next.
> - "but a declared (unexpanded) policy always has the "allow" directive." > I think you need to make it more clear that "allow" is mandatory. But > what was the logic behind making it so? Why not assume "allow *", which > is what browsers do in the absence of CSP anyway?
Sid did address this one, but I want to be clear in the rationale. Once we see the Content Security Policy header (or meta tag), we want to force sites to be explicit about what they are allowing. Yes, "allow *" is the default browser behavior without CSP presently, but we want to avoid cases where sites assume the default behavior of CSP is more restrictive than it actually is. I could envision, for example, a site presuming that "allow none" or "allow self" was the default, and that additional policy could be specified from there. If a site really wants to "allow *", then we want them to explicitly state that.
> - "policy-uri documents must be served with the MIME type > text/content-security-policy to be valid" This probably needs an "x-" > until we've registered it, which we should do before deployment. It's > not a complex process, I hear.
That sounds fair. I'll update the document with that change.
> - "Hostname, including an optional leading wildcard, e.g. *.mozilla.org" > Does that include foo.bar.baz.mozilla.org? If so, we should say so > explicitly (in both docs).
That's true too. I'll make the language more clear.
Gervase Markham wrote: > - "but a declared (unexpanded) policy always has the "allow" directive." > I think you need to make it more clear that "allow" is mandatory. But > what was the logic behind making it so? Why not assume "allow *", which > is what browsers do in the absence of CSP anyway?
"allow" is not mandatory, but if missing it's assumed to be "allow none". If you explicitly specify the whitelisted hosts for each type of load you might not need or want a global fallback which could only be used to sneak through types you hadn't thought about. Future browser features, for instance.
Maybe this does point out the need for some kind of version number in the header, so future browsers can take appropriate action when encountering an old header. For example, assuming "none" for any newly added types.
> - "policy-uri documents must be served with the MIME type > text/content-security-policy to be valid" This probably needs an "x-" > until we've registered it, which we should do before deployment. It's > not a complex process, I hear.
Until we get CSP onto a standards track they'd probably want us to use a text/vnd.mozilla.something, and since we'd like other browsers to support this I vote we go for the "x-" for now.
> On Apr 4, 10:39 am, Florian Weimer <f...@deneb.enyo.de> wrote: >> The policy does not say explicitly what happens to javascript: >> hyperlinks and the on* event handlers.
> Personally, I don't like the idea of honoring redirects for logging... > if a meta tag can be injected into a page (with a CSP header or not) and > the site hosts an open redirect, suddenly cookies can be stolen from all > visitors to a site.
Surely not? If Site Angelic redirects to Site Be-Evil, We don't send Angelic's cookies to Be-Evil, do we? Or have I missed something? You may need to describe the attack scenario in more detail for my small brain.
> While it's true that this would be easy to implement, I think we need to > set a limit. We don't want to spawn off 100 requests every time a policy > is violated. If that happens, attackers could leverage the reporting > mechanism in CSP to flood a network with traffic.
But are there not easier ways of doing this - injecting <img> tags for 100 images on the target server, for example? Given that the reports are so small, I can't see how anyone would want to use it as a DOS mechanism.
We should set a limit. I'm just wondering whether "2" is the most convenient limit.
> I'm not convinced that > widespread use will demand more than two report URIs, and it's not > difficult to set up that report URI recipient service to fork copies to > multiple other destinations.
True. It's not a big deal.
> I think the intention for requiring the allow directive was to force the > policy-writer into writing out the default case to minimize possibility > for false assumptions. I'm not sure though.
Fair enough. As long as the JS console/error report says something sensible if it's missing.
> Maybe this does point out the need for some kind of version number in > the header, so future browsers can take appropriate action when > encountering an old header. For example, assuming "none" for any newly > added types.
I much prefer forwardly-compatible designs to version numbers. I think the current design is forwardly-compatible, as long as we maintain a well-signposted public page listing which category all sorts of request fall into, and add new request types well before they get implemented by anyone.
For example, if a <3dvideo> tag, for which you needed red-blue glasses, made it into a draft HTML5 spec, we would decide and say loudly that this was included in "media-src" well before anyone actually implemented it.
Can you suggest a scenario in which version numbers would help?
> We have been working hard lately to finish documenting the Content > Security Policy proposal,
What's the story on inline <style> and style=""? At the moment the definition of "style-src" says they are subject to it, but there's no valid value for "in this document", and in the script case, all inline script is disabled.
Have we decided that there's a risk with all inline CSS style, or can we define and enforce a large safe subset of the language? Making people move their JS to external files is one thing, making them move all the style as well is yet another.
> Surely not? If Site Angelic redirects to Site Be-Evil, We don't send > Angelic's cookies to Be-Evil, do we? Or have I missed something? You may > need to describe the attack scenario in more detail for my small brain.
Since the user's entire request header is in the report, any cookies sent with the request header to Angelic get forwarded on. While Be-Evil doesn't actually get forwarded cookies, the cookies are buried in the content of the report that is forwarded under the <request-headers> field.
>> I think the intention for requiring the allow directive was to force the >> policy-writer into writing out the default case to minimize possibility >> for false assumptions. I'm not sure though.
> Fair enough. As long as the JS console/error report says something > sensible if it's missing.
Of course. Any forgivable but bad policy syntax is going to be spat into the error console. Terminal ("can't parse") errors will cause CSP to fail closed ("allow self") and still raise an error.
> What's the story on inline <style> and style=""? At the moment the > definition of "style-src" says they are subject to it, but there's no > valid value for "in this document", and in the script case, all inline > script is disabled.
As you mentioned, the style-src section indicates "...as well as inline <style> elements and style attributes of HTML elements." We are basically treating CSS in the same manner as JavaScript.
> Have we decided that there's a risk with all inline CSS style, or can we > define and enforce a large safe subset of the language? Making people > move their JS to external files is one thing, making them move all the > style as well is yet another.
Since style is a vector for JavaScript, via XBL, it needs to be subject to the same restrictions.
> "allow" is not mandatory, but if missing it's assumed to be "allow > none". If you explicitly specify the whitelisted hosts for each type of > load you might not need or want a global fallback which could only be > used to sneak through types you hadn't thought about. Future browser > features, for instance.
See comments from me and Sid from yesterday explaining why allow is required.
I somewhat agree with the spirit of Dan's comment. If allow is not specified, then the _effect_ is to allow none, because the policy is invalid and CSP will fail closed. However, strictly speaking, we don't assume allow none if it isn't specified. We will treat that as invalid policy, logging an error, and not loading any of the content types.
By falling back to "allow none" when invalid policy is sent, websites will know right away that their pages are broken because no content, other than textual elements will load. This is a more secure option than failing open and having websites potentially believe their users are protected.
> On 07/04/09 07:36, Daniel Veditz wrote: >> Maybe this does point out the need for some kind of version number in >> the header, so future browsers can take appropriate action when >> encountering an old header. For example, assuming "none" for any newly >> added types.
> I much prefer forwardly-compatible designs to version numbers.
It has to work both ways; old CSP clients need to be able to parse new CSP rules that are unknown to them and new CSP clients need to be able to parse old CSP rules. Where it will become a challenge is anytime something implicit has its meaning changed (e.g. the default is "x" in CSPv1 and "y" in CSPv2).
> I much prefer forwardly-compatible designs to version numbers. I think > the current design is forwardly-compatible, as long as we maintain a > well-signposted public page listing which category all sorts of request > fall into, and add new request types well before they get implemented by > anyone.
> For example, if a <3dvideo> tag, for which you needed red-blue glasses, > made it into a draft HTML5 spec, we would decide and say loudly that > this was included in "media-src" well before anyone actually implemented > it.
> Can you suggest a scenario in which version numbers would help?
I think the case for including a version number goes something like this (and strong advocates, please chime in if I miss something):
1. Bugs may be present in the CSP design which require future compatibility breakage. These obviously cannot be foreseen and, though we desire it, we can't guarantee forward compatibility.
2. New types of content (per your example) or new web APIs may be added in the future which don't shoehorn nicely into one of our current policy buckets. If we have to add another policy directive in the future, then it will violate the policy syntax in older versions which will cause them to fail closed (according to the current design).
3. We arguably want to have a pref for users to turn off CSP (for testing or otherwise). It would be useful to have the version number available as a means to communicate to the site that, even though the client supports CSP by default, CSP has been disabled on this client.
I looked at each of the HTTP Header Field Definitions and my preference for communicating the CSP version is to add a product token [1] to the User-Agent [2] string. This would add only a few bytes to the U-A and it saves us the trouble of having to go through IETF processes of creating a new request header.
>> Have we decided that there's a risk with all inline CSS style, or can we >> define and enforce a large safe subset of the language? Making people >> move their JS to external files is one thing, making them move all the >> style as well is yet another.
> Since style is a vector for JavaScript, via XBL, it needs to be subject > to the same restrictions.
Actually, my reasoning is wrong here.
Style is no longer a vector for script under CSP because we added the restriction that "XBL bindings must come from chrome: or resource: URIs" for precisely this reason.
The other reason to make inline CSS subject to the style-src directive (which I didn't state before because it didn't seem as strong a point) is increased consistency in the model. It seems inconsistent to offer controls on where style can come from if the restriction can be bypassed by injecting CSS directly into the document. Granted, injected CSS poses a much, much lower risk than injected script, but there is still the issue of page defacement, etc.
I don't think the no-inline-style requirement is too punitive, though, as sites can still use normal CSS selectors and apply their styles from external, white-listed stylesheets.
> I looked at each of the HTTP Header Field Definitions and my preference > for communicating the CSP version is to add a product token [1] to the > User-Agent [2] string. This would add only a few bytes to the U-A and > it saves us the trouble of having to go through IETF processes of > creating a new request header.
I agree that creating a request header for just the CSP version is overkill. However, I am concerned that privacy add-ons, proxies, firewalls, etc may strip or replace the User-Agent string.
I propose a new request header is created, but instead of one that is specific to CSP, it is something more generic that can be used in the future by similar policy frameworks.
I originally came up with Accept-Header during a conversation about revising the Cookie specification; it would alert the server that the client understood "version 3" of cookies:
Accept-Header: Set-Cookie version=3
So it does have a variety of uses that may make it worth the effort to register and define.
> Since the user's entire request header is in the report, any cookies > sent with the request header to Angelic get forwarded on. While Be-Evil > doesn't actually get forwarded cookies, the cookies are buried in the > content of the report that is forwarded under the <request-headers> field.
OK. Then we need to spec that redirects are not honoured.
> Since the user's entire request header is in the report, any cookies > sent with the request header to Angelic get forwarded on. While Be-Evil > doesn't actually get forwarded cookies, the cookies are buried in the > content of the report that is forwarded under the <request-headers> field.
... (following on from previous message) or we need to say that sites with open redirects are already broken, and this is just another symptom, and we should support redirects for the convenience and reduced implementation complexity.
> 1. Bugs may be present in the CSP design which require future > compatibility breakage. These obviously cannot be foreseen and, though > we desire it, we can't guarantee forward compatibility.
There are two sorts of possible breakage - syntax and functional. I can't see us needing to throw away the syntax and, if we did, we'd just define a new header. So no issues there. And functional breakage comes into your second category anyway.
> 2. New types of content (per your example) or new web APIs may be added > in the future which don't shoehorn nicely into one of our current policy > buckets. If we have to add another policy directive in the future, then > it will violate the policy syntax in older versions which will cause > them to fail closed (according to the current design).
But the old browsers also won't support the new APIs/whatever. If we add a <3dcanvas> element to Firefox and control it with 3dcanvas-src, then old browsers won't understand the element, and so ignore it. And so if the browser didn't understand 3dcanvas-src either, that's no big deal.
CSP should specify that unknown directives are ignored. That's a fairly common way to deal with this problem (CSS, HTML etc.).
The only problem would be if an existing browser feature acquires specific restrictions when it used to be covered by "all". In that case, users of old browsers would get less protection - but they had that anyway, because their CSP implementation doesn't support the extra restriction.
> 3. We arguably want to have a pref for users to turn off CSP (for > testing or otherwise). It would be useful to have the version number > available as a means to communicate to the site that, even though the > client supports CSP by default, CSP has been disabled on this client.
Why is that useful information?
I'm actually against making it easy for servers to "detect" if CSP is supported, because if we make it particularly easy, content authors will start relying on it as their only defence rather than using it as a backup. "We don't need to check for XSS holes, we use CSP." That would be bad. Of course, we can't stop them putting together fragile User-Agent lists, but sites which do that are broken anyway, as the web design community has been saying for years.
> I looked at each of the HTTP Header Field Definitions and my preference > for communicating the CSP version is to add a product token [1] to the > User-Agent [2] string. This would add only a few bytes to the U-A and > it saves us the trouble of having to go through IETF processes of > creating a new request header.
I'd much rather have a "\d+;" at the start of the header. Missing implies version 1.
> On 07/04/09 18:02, Brandon Sterne wrote: > I'm actually against making it easy for servers to "detect" if CSP is > supported, because if we make it particularly easy, content authors will > start relying on it as their only defence rather than using it as a > backup. "We don't need to check for XSS holes, we use CSP." That would > be bad. Of course, we can't stop them putting together fragile > User-Agent lists, but sites which do that are broken anyway, as the web > design community has been saying for years.
It seems unlikely that responsible web developers would rely entirely on CSP, especially initially, since not all UAs will support it. And if the developer really does choose to rely entirely on CSP, there isn't much we can do -- any developer with two domains can easily test if the client supports CSP, request header or no header.
I think the stronger likelihood is that the developer won't use CSP at all -- their site will still work regardless. Providing a CSP header that can be measured to show it's worth the effort to learn and implement will be a much stronger incentive.
In summary, given the number of XSS holes out there, if the developer chooses to rely entirely on CSP to protect them, that's far better than not using CSP at all. The biggest threat to CSP is not over-reliance, but rather under-utilization.
> On 07/04/09 18:02, Brandon Sterne wrote: >> 1. Bugs may be present in the CSP design which require future >> compatibility breakage. These obviously cannot be foreseen and, though >> we desire it, we can't guarantee forward compatibility.
> There are two sorts of possible breakage - syntax and functional. I > can't see us needing to throw away the syntax and, if we did, we'd just > define a new header. So no issues there. And functional breakage comes > into your second category anyway.
Defining a new header seems like a non-starter to me. We are going to be hard-pressed to get one new header standardized, so throwing one away seems very wasteful.
>> 3. We arguably want to have a pref for users to turn off CSP (for >> testing or otherwise). It would be useful to have the version number >> available as a means to communicate to the site that, even though the >> client supports CSP by default, CSP has been disabled on this client.
> Why is that useful information?
If sites are relying on CSP for XSS protection, then perhaps they would want to serve only "trusted content" to non-CSP users.
> I'm actually against making it easy for servers to "detect" if CSP is > supported, because if we make it particularly easy, content authors will > start relying on it as their only defence rather than using it as a > backup. "We don't need to check for XSS holes, we use CSP." That would > be bad. Of course, we can't stop them putting together fragile > User-Agent lists, but sites which do that are broken anyway, as the web > design community has been saying for years.
In reality, as CSP becomes more mature and well-understood, sites will rely on it for XSS mitigation. It's inevitable that if we put a reliable product out there sites will rely upon it. CSP won't cause input sanitization, etc. to be removed from Security Best Practices, but it will be a standard part of the browser security model, I imagine.
>> I looked at each of the HTTP Header Field Definitions and my preference >> for communicating the CSP version is to add a product token [1] to the >> User-Agent [2] string. This would add only a few bytes to the U-A and >> it saves us the trouble of having to go through IETF processes of >> creating a new request header.
> I'd much rather have a "\d+;" at the start of the header. Missing > implies version 1.
But our header is only sent as a response header, so would not be useful for sending version info with client requests. We're somewhat averse to adding a request header that would only carry the version info, so that's why we're looking for an existing request header that can carry this info.