- From: Michaela Merz <michaela.merz@rollofone.com>
- Date: Thu, 21 Jan 2016 17:06:46 -0600
- To: public-webappsec@w3.org
David:
I very much appreciate this suggestion. And it most certainly helps a
lot. What makes it a little less useful is the need to again pre-screen
the data that actually ends up within the safeDiv because .. as I
understand it " ... untrusted markup injected into the Safe Node markup
could prematurely close the Safe Node..."
Michaela
On 01/21/2016 04:52 PM, David Ross wrote:
> Mike West, Mario Heiderich, and myself had a conversation recently
> just beginning to explore what sanitization baked into the browser
> might look like. Of course this is not a new concept, with Internet
> Explorer’s ".toStaticHTML()" method having come and gone. Perhaps it
> was ahead of its time. =)
>
> I think we’re beginning to achieve consensus that browser-native
> client-side sanitization would be a boon for web apps. Thinking about
> that got me wondering if maybe there’s a way to achieve the desired
> effect without actually implementing all the complexity of markup
> sanitization. I started to imagine a "Safe Node" in the DOM tree that
> logically enforces various policies on the nodes beneath it.
> Unsurprisingly I’m not the first person to have thought of this, as
> Michael Zalewski had the same idea a number of years back. Perhaps
> this is an idea whose time has finally come.
>
> So here is a strawman proposal for a Safe Node in the DOM. Please
> don’t focus on syntax, but rather take a look at the idea overall and
> try to identify any fatal flaws or areas for improvement.
>
>
> Example Safe Node Usage
>
> var safeDiv = document.createElement("DIV");
> var safeAttribute = document.createAttribute("safety");
> safeAttribute.value = "Enabled: true; DownloadExternalContent: false; ...";
> safeDiv.setAttributeNode(safeAttribute);
> safeDiv.innerHTML = untrustedMarkup;
> document.body.appendChild(safeDiv);
>
> Insert safeDiv into the DOM tree as shown and it will safely contain
> untrusted markup.
>
> Policy enforcement configuration is set on an attribute of the Safe
> Node ("DownloadExternalContent" in the example). If you check the
> markup of the previously created DIV like this:
>
> outputMarkup = safeDiv.outerHTML;
>
> ...at this point outputMarkup might look something like this:
>
> <div safety="Enabled: true; DownloadExternalContent: false;
> ...">[untrusted markup]</div>
>
> It is possible to integrate markup from various sources that will
> ultimately be rendered later. Or in applications that aren’t as
> complex, it’s easy to simply output untrusted markup into Safe Nodes
> that are immediately added into the document.
>
> Safety is enforced by the fact that the untrusted markup is contained
> within a Safe Node. Breakout is prevented by the design pattern shown
> above. (e.g.: Setting innerHTML will inherently never allow breaking
> out of the containing node.)
>
>
> Policies capable of being enforced
>
> Policies would match those that a sanitizer would also be capable of
> enforcing to prevent content that may or may not be malicious.
>
> Policies set to be enabled by default:
>
> * Disablement of script / active content
> * Disablement of frames
> * No support for FORM elements (to prevent phishing)
> + Input elements such as INPUT, BUTTON, etc. still allowed
> * Disablement of link targeting
> * Supported protocols limited to https://
> * Safe CSS
> + Prevent anti-XSRF nonce theft via CSS
> + Prevent UI overlay
> + Prevent any identified abuse of existing styles on the page
> + Prevent styles defined within the Safe Node from affecting the
> surrounding page
>
> Optional policies:
>
> * Max width / height
> + To prevent outside UI from being pushed out of the way
> * Allow links
> * List of protocols to allow in URLs, beyond https://
> * Flag to regulate use of relative URLs
> * Flag to regulate use of multimedia (e.g.: AUDIO and VIDEO elements)
> * Flag to regulate use of external content
> + Callback for handling external content
>
> This list was derived from Michal Zalewski’s previous work and my own
> experience with implementation of client-side sanitization.
>
> Right now the list above covers the policies that would make sense to
> regulate however it does not specify syntax. When the syntax is
> ultimately defined, it would seem to make the most sense to adopt
> existing conventions if possible (e.g.: Maybe the FORM policy maps
> well to frame sandbox "allow-forms"?).
>
>
> Pros (relative to sanitization)
>
> 1) Elimination of sanitization complexity.
>
> It’s much easier to implement a policy such as "disable script under
> this node" than it is to implement sanitizer logic to optimally
> achieve the same result. Since we are in the browser, it's possible
> to avoid creating a DOM and then walking through it as would be
> required for sanitization.
>
> E.g.: How do you properly sanitize SVG? This is difficult for a
> traditional client-side sanitizer to get right. Answer: Mostly we
> don’t care, we just enforce that script is disabled below a given
> node, clipping is enforced, etc. as per configuration of the Safe
> Node.
>
> 2) It's only natural for enforcement of policy to be integrated with
> the actual implementation of the code on which the policy is being
> enforced.
>
> 3) It’s easier for a Safe Node to safely handle CSS than it would be
> for a client-side sanitizer.
>
> A client-side sanitizer has no visibility into externally downloaded
> stylesheets. (Though this may not be an issue with a sanitizer built
> into the browser, given that it could effectively regulate downloaded
> stylesheets.)
>
> It’s also difficult for client-side sanitizers to correctly handle
> inline STYLE elements as there is no real DOM for a STYLE element.
> It’s not easy for a client-side sanitizer to effectively constrain
> unsafe styles to within a given element.
>
>
> Cons (relative to sanitization)
>
> 1) Being able to get sanitized markup is a feature that could have
> non-niche use cases that have yet to be identified.
>
>
> FAQ
>
> Q: How is this different from IFRAMES? Seamless IFRAMEs?
> A: IFRAMEs are clumsy in that they contain a different document, CSS
> doesn’t apply, and they are rectangular. Seamless IFRAMEs take care
> of two of those problems, but they seem to have been abandoned as a
> proposal for standardization.
>
> Q: If you have some markup with a Safe Node in it, is that safe?
> A: Best practice: Always output unsafe markup into a Safe Node that
> you (the host) have created. If you do need to manipulate markup
> containing a Safe Node and then output that markup directly onto the
> page, remember to treat the Safe Node string as an atomic unit.
> Untrusted markup injected into the Safe Node markup could prematurely
> close the Safe Node.
>
> Q: Can you manipulate the DOM underneath a Safe Node?
> A: Sure! If a SCRIPT node is created or moved to within the Safe
> Node, for example, it simply does not execute script. Of course it
> would not be secure to pull nodes out from within a safe tree and move
> them elsewhere in the DOM, outside of a safe node.
>
> Q: Why not implement a "safe innerHTML" instead of a Safe Node?
> A: The Safe Node paradigm makes it easy to store configuration
> parameters in an attribute on the element. Also, apparently
> .innerHTML is not available in SVG.
>
>
> Todo
>
> Is there a convenient and safe way to enable script from outside the
> Safe Node to set an event handler on markup existing within the safe
> node? It should be possible to do this safely in some fashion. We
> would certainly need to consider the possibility of DOM clobbering
> though and ensure best practice is immune to that.
>
> Thoughts? The key question: Is this proposal better or worse than
> more traditional client-side sanitization baked into a browser API?
>
>
> References
>
> Michael Zalewski has previously proposed a very similar idea.
>
> The list of policies for enforcement was inspired by Michael’s work on
> and also by my own work on the jSanity client-side sanitizer.
>
>
> Dave
>
Received on Friday, 22 January 2016 08:33:24 UTC