Re: 'strict-dynamic' syntax (was Re: On the Insecurity of Whitelists and the Future of CSP)

On Fri, Sep 9, 2016 at 11:29 AM, Mike West <mkwst@google.com> wrote:

> Before getting too deep into the weeds, how opposed are you to the
> currently specified syntax? :)
>
> Using Google's implementation experience as a basis, Artur, et al. have
> been putting together a good deal of ancillary material and tooling to
> educate/assist developers with regard to preventing XSS with
> `'strict-dynamic'`. It seemed reasonable to do so after the discussions
> referenced earlier in the thread, but if Mozilla turns out to be strongly
> opposed to the syntax, then they'll probably need to hold off on
> publication (and potentially recall already published papers like the one
> we're discussing in the other thread) in order to reduce developer
> confusion. That would be a shame.
>
> On Fri, Sep 9, 2016 at 9:32 AM, Daniel Veditz <dveditz@mozilla.com> wrote:
>
>> On 9/8/16 1:25 PM, Artur Janc wrote:
>> > - There is already an "ignore" mechanism in CSP, which works within a
>> > single directive, namely the presence of 'nonce-*' or 'sha*' ignores
>> > 'unsafe-inline' for backwards-compatibility.
>>
>> ... which was an ugly but necessary hack in CSP2.
>
>
> "Ugly but necessary" describes much of CSP, doesn't it? :)
>
>
>> The directive-level override was built-in from the beginning, with *-src
>> directives
>> overriding default-src, and later frame-src overriding child-src.
>>
>
> This seems to reinforce Artur's central point: CSP has overriding
> mechanisms built in from the beginning, and we've historically added new
> features (like 'nonce-*') by extending the overrides. It seems reasonable
> to call that mechanism "normal" at this point.
>
> > you need to pay attention to different directives deciding the same
>> > behavior, understand which wins out in which browser, etc. I'd argue
>> > it's just as confusing, if not more :(
>>
>> Seems much easier to understand to me: use script policy-A in old
>> browsers and script policy-B in new browsers, one or the other, a choice
>> of two. with 'strict-dynamic' a keyword you are mentally understanding a
>> policy as one thing until you hit that keyword--which could be
>> anywhere--and then you have to backtrack to figure out what parts are
>> actually ignored.
>>
>
> I'm still not terribly clear on your proposal, Dan. Is it something like
> the following?
>
> ```
>     script-src 'unsafe-inline' https: 'nonce-abcdefg'; dynamic-script-src
> 'nonce-abcdefg'
> ```
>
> If that strawman is something like what you'd like to see, then I'd
> naively claim that an aversion to "backtracking" is equally relevant: "Oh,
> they're whitelisting inline script and `https:`. Oh, wait, no. There's a
> nonce, so no 'unsafe-inline'. Oh, wait, no. There's this other directive.
> So they're dynamically whitelisting nonced sources. Got it."
>
>
>> > - A new directive likely wouldn't be able to completely ignore
>> > script-src, because it would need the nonce defined therein. Or
>> > otherwise we would force the developer to include the nonce in both
>> > places (script-src 'nonce-foo123' [something]; new-script-src
>> > 'nonce-foo123';) for backwards-compatibility, which seems fairly
>> inelegant.
>>
>> Yes, if you used the nonce in the CSP2-level policy you'd have to repeat
>> it. I agree it's more verbose but that's not necessarily inelegant.
>>
>
> Arguing about "elegance" is unlikely to get us anywhere, as I think it's
> clear that CSP's syntax isn't, and isn't going to be. :)
>
> I'd suggest that the verbosity introduces opportunities to screw things
> up, in that you'll need to ensure that the nonce is repeated correctly, and
> you don't accidentally generate a new one when processing the CSP template.
>

I brought up elegance first, which was probably wrong, so I apologize. I
meant it in the sense that Mike explained it, i.e. by definition you're
supposed to generate a new nonce every time but now you'd have to reuse it
to fill in different parts of your policy (or else your site would break
for some users). Note that this also applies to other sources supported by
script-src such as 'unsafe-eval' or hashes -- I expect you'd need to
duplicate all of them in the new directive, which for long strings such as
hashes would contribute to making the policy less readable.


>
> > many applications can avoid the whitelist altogether to get around
>> > the adoption/maintenance difficulties, and serve a policy such as
>> > "script-src 'nonce-foo' 'strict-dynamic' 'unsafe-inline' https:" where
>> > the last two entries will be ignored.
>>
>> That policy does almost nothing to protect a site in a browser that does
>> not honor 'strict-dynamic'.
>
>
> 1. The claim in the paper discussed in the other thread is that many
> whitelists are equally lacking in protective power.
>
> 2. We're all going to ship `'strict-dynamic'`, right? So this won't be a
> problem in a year. :)
>
> > Second, if the developer wants to
>> > maintain a whitelist for older browsers, it's easy to split this into
>> > two separate CSP policies, where the original one will be unchanged, and
>> > the new CSP header will only focus on nonce enforcement (same policy as
>> > above). We have some experience that suggests that even developers
>> > unfamiliar with CSP can grok this.
>>
>> Yes, that works. Duplicating most of two entire policies seems more
>> 'inelegant' to me than duplicating a nonce across two directives, but
>> that's the kind of clarity I was going for.
>>
>
> Artur can correct me if I'm wrong, but I believe that some Google
> properties are doing this today to get both the XSS protection of nonces +
> dynamism, and the architectural restrictions of whitelists.
>

Yes, we're doing it in a couple large products and frameworks
(unfortunately only visible internally now). However, in practice, we're
not duplicating a significant part of the policy. A concrete example is:
[original policy] Content-Security-Policy: script-src 'unsafe-inline' [~30
whitelisted hosts]; [5 other directives, ~50 whitelisted
hosts]; upgrade-insecure-requests, etc.
[added policy] Content-Security-Policy: script-src 'nonce-foo'
'strict-dynamic' 'unsafe-inline' https:

The duplication here is 'unsafe-inline' and that's only for
backwards-compatibility. There's also a logical separation between what the
policies do -- the first one enforces a whitelist (and is unchanged), and
the second one serves to protect against XSS. The added benefit is that the
second policy can be separately put in Report-Only mode for testing, and
have its own report-uri. I believe that with a new directive it would also
be necessary to put it in a separate policy for those reasons, at which
point the approaches would be identical, save for the new directive name
and lack of the fallbacks.

Cheers,
-Artur

Received on Friday, 9 September 2016 12:21:50 UTC