Making it easier to deploy CSP.

Hello, lovely webappsecians!

I've been talking to Google's security folks about their adventures in
deploying CSP to Google products. The TL;DR is that they're scared of
whitelists (because of all the legacy junk on `google.com` and `
googleapis.com`), and are frustrated with loading widgets and libraries
whose content they don't control. They love (cryptographic) nonces and
hashes, and have a small proposal for a new source expression which would
make deployment at Google (and hopefully elsewhere) easier.

# Whitelists

As it turns out, `google.com` and other origins we depend on are full of
terrible endpoints that allow user-injected script (see `
https://github.com/cure53/XSSChallengeWiki/wiki/H5SC-Minichallenge-3:-%22Sh*t,-it's-CSP!%22`,
for example). We mitigate this risk with extensive `script-src` directives
full of deep paths, which is brittle, awkward, and sometimes impossible
(because some folks dynamically generate all the things!). It's also
vulnerable to open redirects stripping the path, and of course sprawling
origins like ours have open redirects too. Huzzah for legacy!

The security team here would be thrilled if they could use (cryptographic)
nonces and hashes for everything instead of relying on whitelists.

But:

# Dynamic Content

Widgets and libraries make this dream difficult, as they insist on loading
code from various places, and don't do a good job explaining what code
they'll actually need before doing so (I'm looking at you, Google Maps). We
can certainly add all of these paths to the whitelists as well, but they
change on a somewhat regular basis, and end up with the same drawbacks as
noted above.

As it turns out, in the presence of a (cryptographic) nonce, this is
something that the library itself could deal with, by grabbing the token
from somewhere on the page, and using it when injecting its own script. The
token is implicitly a script-execution capability:

```
var ce = document.createElement;
window.nonce =
document.querySelector('script[nonce]').getAttribute('nonce');
document.createElement = function (e) {
 var el = ce.apply(this, arguments);
 el.setAttribute('nonce', window.nonce);
 return el;
};
```

While we work on updating every library in the entire world to use this
pattern, we're also experimenting with getting the browser to do the
busywork for us, in a backwards compatible way:

# 'unsafe-dynamic'

We're proposing a new `'unsafe-dynamic'` source expression which has the
following effects when added to the `script-src` directive:

1.  If neither a hash nor a nonce is present in the directive's source
list, do nothing. Otherwise:

2.  Ignore all `scheme-source` and `host-source`source expressions, as well
as `'unsafe-inline'`. This gives us backwards compatibility, and ensures
that developers who opt-into this mechanism won't leave themselves open to
whitelist-based vulnerabilities; if you use 'unsafe-dynamic', that's all
you use. That is, given the policy: `script-src 'unsafe-inline'
https://example.com/ 'nonce-abcdef' 'unsafe-dynamic'`, Safari would see
`script-src 'unsafe-inline' https://example.com/` (as it doesn't support
nonces, while supporting browsers would see `script-src 'nonce-abcdef'
'unsafe-dynamic'`.

3.  Skip CSP enforcement on script execution for `<script>` elements which
are not "parser-inserted". This basically boils down to automatically
applying the capability noted above for scripts inserted via something like
`appendChild(createElement('script'))`. We're only focusing on
non-parser-inserted scripts, as (anecdotally) `document.write` and
`innerHTML` are significantly more likely to contribute to XSS than
`appendChild`. Moreover, `appendChild` accounts for the large majority of
intentionally inserted scripts, based on an analysis of several dozen
popular origins.

You can play with most of this in Chrome Canary (behind
chrome://flags/#enable-experimental-web-platform-features). Based on some
experimentation with a crazy nonce-injecting extension, a policy like
`'unsafe-eval' 'nonce-abcdef' 'unsafe-dynamic'` allows strict whitelisting
with very little breakage on various Google properties and a few other high
profile sites. The folks I've CC'd have more details on those tests for
y'all if you're interested.

I'll write up a patch to CSP to spell this out in more detail, but I hope
the overview here is enough to get some early feedback. :)

-mike

Received on Friday, 12 February 2016 13:57:55 UTC