I'll try to find the time to write a complete specification.
> I believe you advocate a model where a site specifies the directives it
> knows/cares about, and everything else is allowed.
The design I suggest is simpler than this. The site just lists which
restrictions it would like applied to its content. Each directive is
purely subtractive: adding more directives only further restricts what
the site can do.
> This model would make
> the default "allow" directive unnecessary. The main idea is to allow sites
> to restrict the things it knows about and not have to worry about
> inadvertently blocking things it doesn't consider a risk.
That's correct. I also think it makes sense to package the
restrictions into "meaningful" directives that address specific
threats.
> My main objection to this approach is that it turns the whitelist approach
> we started with into a hybrid whitelist/blacklist.
The design is a pure blacklist. Just like turning off unused
operating system services, content restrictions should let web
developers turn off features they aren't using.
> The proposal doesn't
> support the simple use case of a site saying:
> "I only want the following things (e.g. script and images from myself).
> Disallow everything else."
The problem is that "everything else" is ill-defined. Should we turn
off canvas? That's a "thing" that's not a script or an image from
myself. CSP, as currently design, as a hard-coded universe of
"things" it cares about, which limits its use as a platform for
addressing future use cases. It is a poor protocol that doesn't plan
for future extensibility.
> Under your proposal, this site needs to explicitly opt-out of every
> directive, including any new directives that get added in the future.
Not really. When we invent new directives, sites can opt in to them
by adding them to their policy. Just like you can opt in to new HTML5
features by adding new HTML tags to your document.
> We're
> essentially forcing sites to maintain an exhaustive blacklist for all time
> in order to avoid us (browsers) accidentally blocking things in the future
> that the site forgot to whitelist.
Web developers are free to ignore CSP directives that mitigate threats
they don't care about. There is no need for web developers to
maintain an exhaustive list of anything.
> Under your proposed model, a site will continue to "function correctly" only
> in the sense that nothing will be blocked in newer implementations of CSP
> that wouldn't also have been blocked in a legacy implementation.
That's correct. The semantics of a given CSP policy does not change
as new directives are invented and added to the language, just as the
semantics of an old HTML document doesn't change just because we
invented the canvas tag.
> From my
> perspective, the blocking occurs when something unexpected by the site was
> included in the page. In our model, the newer implementation, while
> potentially creating an inconsistency with the older version, has also
> potentially blocked an attack.
You're extremely focused on load resources and missing the bigger picture.
> Are you suggesting that a blocked resource is more likely to have come from
> a web developer who forgot to update the CSP when s/he added new content
> than it is to have been injected by an attacker?
I'm not suggesting this at all. Nothing in my argument has to do with
probabilities.
> This seems like a
> dangerous assumption. All we are getting, in this case, is better
> consistency in behavior from CSP implementation-to-implementation, but not
> better security.
Consistency between implementation is essential. Mitigating important
threats is also essential. Nether is more important than the other.
>> 2) Modularity. We would be free to group the directives into whatever
>> modules we liked because there would be no technical interdependence.
>
> I actually don't see how opt-in vs. opt-out has any bearing at all on module
> interdependence. Maybe you can provide an example?
Sure. Suppose I want to implement enough of CSP to let web developers
protect themselves from Type-I and Type-II XSS (e.g., because I view
that the lion's share of the benefit). How can I do that in the
current CSP design without affecting the targets of XMLHttpRequest?
Surely you agree that restricting the targets of XMLHttpRequests has
little (if anything) to do with mitigating Type-I or Type-II XSS, yet
these parts of CSP are so interdependent that I'm forced to implement
all of them or none of them.
> Let's also not forget that CSP modularity really only helps browser vendors.
Complexity hurts everyone. The current monolithic CSP design is
overly complex for the security it provides. There are much simpler
designs that provide the same security benefits.
> From the perspective of websites, CSP modules are just one more thing that
> they have to keep track of in terms of which browsers support which modules.
In the subtractive design, web developers don't need to care at all
which browsers support which modules. They can simply turn off the
features they're not using. Browsers that understand those modules
will provide additional security. Browsers that don't understand
those modules will be blissfully ignorant.
> I support the idea of making it easier for other browser vendors to
> implement CSP piecemeal, but our primary motivation should remain making the
> lives of websites and their users better.
Again, tightly coupling unrelated concepts leads to complexity and
hurts everyone.
>> 3) Trivial Combination. Instead of the current elaborate algorithm
>> for combining policies, we could simply concatenate the directives.
>> An attacker who could inject a Content-Security-Policy header could
>> then only further reduce his/her privileges.
>
> In the case of an injected header, this is already the case now. We
> intersect both policy sets, resulting in a combined policy more restrictive
> than either of the two separate policies.
The combination algorithm is quite complex. To implement the
algorithm, I need to compute the semantics of both policies and then
interset those semantics. In the design I propose, one simply uses
the standard algorithm for coalescing HTTP headers.
> If we are talking about an attacker who can inject an additional directive
> into an existing CSP header then, yes, the attacker could "relax" the policy
> intended to be set by the site. I'm not sure how much I care about this
> case.
By using a subtractive design, we need not worry about an attacker
injecting policy at all. Injected policy (either into a single HTTP
header field or into an additional HTTP header field) is of no use to
the attacker because the injected directives only disable more
features.
>> 4) Syntactic Simplicity. Instead of two combination operators, ";"
>> for union and "," for intersection, we could simply use "," and match
>> standard HTTP header syntax.
>
> Okay, sure.
>
>> Balancing against these pros, the con seem to be that we hope the
>> additive, opt-out syntax will prod web developers into realizing that
>> adding "script-src inline" to the tutorial code they copy-and-paste is
>> more dangerous than removing "block-xss".
>
> Those seem equivalent to me, so I'm not sure which model your example
> favors.
If those seem equivalent, they why not adopt the less complex, more
extensible design? In this entire email, you haven't stated why we
should prefer the tightly coupled design / opt-out over the modular
opt-in design.
> In general, I'm slightly skeptical of the view that we need to base our
> design around the fact that admins will copy-paste from tutorials.
None of my four points make this argument. I'm not advocating basing
our design on this assumption.
> Sure,
> this will happen in practice, but what is the probability that such a site
> is a high value target for an attacker, and by extension how important is it
> that such a site gets CSP right? Remember, a site cannot make their
> security profile any worse with CSP than without it.
>
> I do want CSP to be easy to get right. I should do some homework and
> collect some stats on real world websites to support the following claim,
> but I still maintain that a HUGE number of sites will be able to benefit
> greatly from a minimal policy such as "allow 'self'". Even "allow *" would
> be a gigantic improvement in terms of blocking all the common XSS vectors.
The "allow *" policy does not mitigate *any* Type-I or Type-II XSS
vulnerabilities. If you, an expert in this topic, does not understand
this fact, then I have little hope that web developers will be able to
understand how to use CSP, as currently designed, correctly.
> My contention is that CSP tutorials should (and will if we evangelize
> properly) instruct sites to start with a minimal policy such as "allow
> 'self'" and incrementally add policy until the site behaves as expected.
> This approach will result in minimal policy set and will tend to be optimal
> in terms of bandwidth and risk profile.
I agree that we should make the most useful policy textual short. No
one is arguing against this proposition.
Adam
I find it rather surreal that we are arguing over whether to implement a
whitelist or a blacklist in CSP. I am strongly in the whitelist camp
and I have seen no strong evidence that reversing the approach is the
right way to go. Are there others who honestly feel a blacklist is a
wise approach?
>> The proposal doesn't
>> support the simple use case of a site saying:
>> "I only want the following things (e.g. script and images from myself).
>> Disallow everything else."
>
> The problem is that "everything else" is ill-defined.
I disagree completely. It's "the things I haven't explicitly approved".
> Should we turn
> off canvas? That's a "thing" that's not a script or an image from
> myself.
So are objects, stylesheets and every other type of content we have
enumerated a policy directive for. We can add other directives if we
think there is value in doing so for specific browser capabilities.
> CSP, as currently design, as a hard-coded universe of
> "things" it cares about, which limits its use as a platform for
> addressing future use cases. It is a poor protocol that doesn't plan
> for future extensibility.
The list of "things" needs to be hard coded whether or not we allow
sites to opt-in or opt-out of using them.
Do you have any support for your claim that we don't plan for future
extensibility? Our proposal is clear that browsers should skip over
directives they don't understand which allows for new directives to be
added in the future.
>> Under your proposal, this site needs to explicitly opt-out of every
>> directive, including any new directives that get added in the future.
>
> Not really. When we invent new directives, sites can opt in to them
> by adding them to their policy. Just like you can opt in to new HTML5
> features by adding new HTML tags to your document.
Remember the use case I gave as an example. Site wants X and Y and
nothing more. In your model, not only _can_ sites add new policy as we
add new directives, they _have to_ if they want to restrict themselves
to X and Y.
>> We're
>> essentially forcing sites to maintain an exhaustive blacklist for all time
>> in order to avoid us (browsers) accidentally blocking things in the future
>> that the site forgot to whitelist.
>
> Web developers are free to ignore CSP directives that mitigate threats
> they don't care about. There is no need for web developers to
> maintain an exhaustive list of anything.
Again, they do if they want to strictly whitelist the types of content
in their site.
>> Under your proposed model, a site will continue to "function correctly" only
>> in the sense that nothing will be blocked in newer implementations of CSP
>> that wouldn't also have been blocked in a legacy implementation.
>
> That's correct. The semantics of a given CSP policy does not change
> as new directives are invented and added to the language, just as the
> semantics of an old HTML document doesn't change just because we
> invented the canvas tag.
We're talking about _unintended_ content being injected in the pages.
If browsers add some risky new feature (and I'm not saying canvas is
that) then a site which doesn't use the feature shouldn't have to update
their policy to stay opted-out. They never opted-in in the first place.
Think "Principle of Least Surprise".
>> From my
>> perspective, the blocking occurs when something unexpected by the site was
>> included in the page. In our model, the newer implementation, while
>> potentially creating an inconsistency with the older version, has also
>> potentially blocked an attack.
>
> You're extremely focused on load resources and missing the bigger picture.
You did not address my point which was one example of how opting-in to
features provides better security.
>> Are you suggesting that a blocked resource is more likely to have come from
>> a web developer who forgot to update the CSP when s/he added new content
>> than it is to have been injected by an attacker?
>
> I'm not suggesting this at all. Nothing in my argument has to do with
> probabilities.
Okay, I'll pose the same question a different way: do you think it is
more important to avoid false positives (allow harmful content through)
than it is to avoid false negatives (block benign content) in the
absence of an explicit policy?
>> This seems like a
>> dangerous assumption. All we are getting, in this case, is better
>> consistency in behavior from CSP implementation-to-implementation, but not
>> better security.
>
> Consistency between implementation is essential. Mitigating important
> threats is also essential. Nether is more important than the other.
I disagree. I don't see how consistency between implementation is as
important as threat mitigation. Isn't the damage that can be done to a
user via an exploited vulnerability worse than what would happen to them
if the site rendered differently than another user with a different browser?
>> From the perspective of websites, CSP modules are just one more thing that
>> they have to keep track of in terms of which browsers support which modules.
>
> In the subtractive design, web developers don't need to care at all
> which browsers support which modules. They can simply turn off the
> features they're not using.
They can only "turn off the features they're not using" in the browsers
that support that module. The same goes for the opt-in method.
My point was that they will have to keep track of modules that are
supported in each browser if they want to keep a clear picture of their
risk profile across all their users.
> Browsers that understand those modules
> will provide additional security. Browsers that don't understand
> those modules will be blissfully ignorant.
The same thing applies to the opt-in model. Browsers that don't
understand some directive will skip over it, not restricting that type
of content loading in any way.
>>> Balancing against these pros, the con seem to be that we hope the
>>> additive, opt-out syntax will prod web developers into realizing that
>>> adding "script-src inline" to the tutorial code they copy-and-paste is
>>> more dangerous than removing "block-xss".
>>
>> Those seem equivalent to me, so I'm not sure which model your example
>> favors.
>
> If those seem equivalent, they why not adopt the less complex, more
> extensible design? In this entire email, you haven't stated why we
> should prefer the tightly coupled design / opt-out over the modular
> opt-in design.
I believe I have provided concrete examples that show that opt-in is a
more secure model. If you really require that I go out and find a bunch
of references for you to further illustrate that a whitelist is a better
security paradigm than a blacklist, I can do that.
>> I do want CSP to be easy to get right. I should do some homework and
>> collect some stats on real world websites to support the following claim,
>> but I still maintain that a HUGE number of sites will be able to benefit
>> greatly from a minimal policy such as "allow 'self'". Even "allow *" would
>> be a gigantic improvement in terms of blocking all the common XSS vectors.
>
> The "allow *" policy does not mitigate *any* Type-I or Type-II XSS
> vulnerabilities. If you, an expert in this topic, does not understand
> this fact, then I have little hope that web developers will be able to
> understand how to use CSP, as currently designed, correctly.
I did make a mistake and you were justified in bludgeoning me with it.
However, what I should have said was "even "allow *" would block _some_
of the common XSS vectors". Your statement that "allow *" does not
mitigate *any* type I or II XSS is wrong. A very common XSS pattern is
attribute injection, where an attacker can't get angle brackets and full
tags injected, but they can inject an event-handling attribute in some
existing element. These vulnerabilities would be mitigated by "allow
*". I apologize for the overstatement.
I look forward to your response and hope we can find a way forward soon.
Cheers,
Brandon
I don't think that is what Adam is arguing about.
Writing protocols for the web is fundamentally different from that for
other systems. A fundamental constraint (amongst others) which you
should support is (random term) 'anarchic' extensibility. 'Anarchic'
in the sense that we don't know what/how the system is going to be
extended and we probably wont have a say in it. Designing under such
constraints, he proposes a policy mechanism which involves
blacklisting only. Current-CSP on the other hand seems to have started
from 'white listing is the most secure way' and then gone on to
develop a mechanism for the web. Whitelisting might be the most
secure way but that doesn't necessarily equate with good for the web.
If you can come up with a mechanism that under these web constraints
is still white list only, you are most welcome.
Don't get me wrong , I do agree with your approach. But the argument
isn't as simple as whitelisting vs. blacklisting -- if you phrase it
that way no security researcher is going to say 'blacklisting'.
Cheers
Devdatta
Purely regarding opt-in vs opt-out:
One significant advantage of the opt-out (of protections) approach
rather than the opt-in approach is that it generally maps well to
common web developer workflows.
The opt-out model generally requires web developers to model their
expected application behavior (which API's they use, that external
advertisers they import, which image servers they use, plugins they
allow, etc.) This only requires knowledge of their expected site
behavior, but little security knowledge. It also has advantages in
testing insofar that the developer only needs to add directives until
their website works properly, which is the type of positive testing
web developers are generally quite good at.
One weakness with opt-in is that it requires the developer to
understand what threats they want to mitigate and implement those
restrictions correctly. This is much harder for web developers to do
from my experience, as it requires significant security knowledge; the
complexity of the policy will always have to be somewhat proportional
to the complexity of the site so I don't think we can design this
problem away. Now I completely agree that given a flexible enough
model (opt-in or opt-out) what you would see develop is common
policies being developed into patterns, so the developer could
hopefully find the right set of patterns to help them implement their
policies, given the right resources and some basic security
knowledge. However, the issue is that the developer still can't
determine if those policies are the strongest policies from a security
standpoint, since its a negative testing problem. So the model I
would recommend for web developers that want optimal security would be
to enable all of the protections, then loosen them individually until
the site works properly. Which is really no different from the opt-
out model. This is a general best practice for securing any
environment (ask anyone in IT).
So it seems regardless of opt-in vs opt-out, the optimal approach for
web developers is to model what their expected environment is and
enable only that functionality. Both models suffer from the same flaw
of course: the developer could enable things that allow their site to
operate properly but also leave them wide open to attack.
I have to say as an aside, there has been a lot of argument about
which model is more extensible or less complex. Frankly that all
seems rather subjective to me and not super productive, so I'd
probably be more effective if nobody assumed their model is inherently
more or less complex as we are not getting any closer to consensus
there. If there are specific areas where we can actually compare
complexity, then please lets just focus on those. So far I haven't
seen a single concrete example. From https://wiki.mozilla.org/Security/CSP/Strawman
(thank you for posting that, btw), they seem largely equivalent in
terms of nature and number of directives. Thanks,
Lucas.