Re: Making it easier to deploy CSP.

-mike

On Wed, Feb 17, 2016 at 3:35 AM, Artur Janc <aaj@google.com> wrote:

> On Mon, Feb 15, 2016 at 1:46 AM, Conrad Irwin <conrad.irwin@gmail.com>
> wrote:
>
>> The behaviour of `unsafe-dynamic` you propose seems pretty confusing to
>> describe to me (you have to distinguish between "parser-inserted" and not),
>> and I'm not sure how it integrates with other browser functionality.
>>
>
> This could likely be simplified to: *scripts created with
> document.createElement('script') *without much loss of generality.
>

"parser-inserted" is an existing concept in the HTML spec that was trivial
to build upon in Chrome's implementation. I apparently left that link out
of the my initial email, sorry:
https://html.spec.whatwg.org/#parser-inserted. If possible, I'd prefer to
rely on those existing concepts, rather than carving out new boundaries.

A particular case I'm confused about is:
>> 1. create a new document with document.implementation.createDocument()
>> 2. use that document to safely parse untrusted HTML (as is done by
>> DOMPurify)
>> 3. use appendChild() to copy nodes from that document into a second
>> document
>>
>> It seems like the scripts would run in that case (assuming the target
>> document had a CSP of `unsafe-dynamic`), even though the scripts were
>> created by the parser?
>>
>
> Interesting... I think either behavior would be acceptable for the
> purposes of unsafe-dynamic so it's a question of what makes more sense for
> the spec and implementations. If you explicitly call
> appendChild([script-from-another-document]) then you are presumably doing
> it intentionally so the script could be blessed to execute. At the same
> time, we could stick to the very narrow definition of "script needs to be
> created with document.createElement()" and in practice the value of
> unsafe-dynamic wouldn't be diminished (the majority of JS APIs and widgets
> will be covered).
>

With the above definition in mind, I don't think this bypass you suggest
will work: pushing data into a document (via something like `var doc =
document.implementation.createHTMLDocument(); doc.body.innerHTML = "<scr" +
"ipt>...</scr" + "ipt>";`) will result in a `<script>` element whose
"parser-inserted" flag is set. Appending that child into a new document
doesn't clear the flag: the element is simply adopted from one context into
the other. I don't believe that something like
`document.body.appendChild(doc.body.firstChild)` would result in script
execution.

I haven't checked that in Chrome, so it's entirely possible that I'm wrong
(or our implementation is wrong! :) ), but I'm fairly certain that's how it
works. +annevk, who will certainly have opinions.

-mike

Received on Wednesday, 17 February 2016 10:53:24 UTC