Re: [webcomponents] More backward-compatible templates

On Nov 1, 2012, at 1:57 PM, Adam Barth <w3c@adambarth.com> wrote:

> 
> 
> (5) The nested template fragment parser operates like the template fragment parser, but with the following additional difference:
>      (a) When a close tag named "+script" is encountered which does not match any currently open script tag:
> 
> Let me try to understand what you've written here concretely:
> 
> 1) We need to change the "end tag open" state to somehow recognize "</+script>" as an end tag rather than as a bogus comment.
> 2) When the tree builder encounter such an end tag in the ???? state(s), we execute the substeps you've outlined below.
> 
> The problem with this approach is that nested templates parse differently than top-level templates.  Consider the following example:
> 
> <script type=template>
>  <b
> </script>
> 
> In this case, none of the nested template parser modifications apply and we'll parse this as normal for HTML.  That means the contents of the template will be "<b" (let's ignore whitespace for simplicity).
> 
> <script type=template>
>   <h1>Inbox</h1>
>   <script type=template>
>     <b
>   </+script>
> </script>
> 
> Unfortunately, the nested template in this example parses differently than it did when it was a top-level template.  The problem is that the characters "</+script>" are not recognized by the tokenizer as an end tag because they are encountered by the nested template fragment parser in the "before attribute name" state.  That means they get treated as some sort of bogus attributes of the <b> tag rather than as an end tag.

OK. Do you believe this to be a serious problem? I feel like inconsistency in the case of a malformed tag is not a very important problem, but perhaps there are cases that would be more obviously problematic, or reasons not obvious to me to be very concerned about cases exactly like this one.

Also: can you think of a way to fix this problem? Or alternately, do you believe it's fundamentally not fixable? I've only spent a short amount of time thinking about this approach, and I am not nearly as much an expert on HTML parsing as you are.


>  
>          (a.i) Consume the token for the close tag named "+script".
>          (a.ii) Crate a DocumentFragment containing that parsed contents of the fragment.
>          (a.iii) [return to the parent template fragment parser] with the result of step (a.ii) with the parent parser to resume after the "+script" close tag.
> 
> 
> This is pretty rough and I'm sure I got some details wrong. But I believe it demonstrates the following properties:
> (B) Allows for perfect fidelity polyfills, because it will manifestly end the template in the same place that an unaware browser would close the <script> element.
> (C) Does not require multiple levels of escaping.
> (A) Can be implemented without changes to the core HTML parser (though you'd need to introduce a new fragment parsing mode).
> 
> I suspect we're quibbling over "no true Scotsman" semantics here, but you obviously need to modify both the HTML tokenizer and tree builder for this approach to work.

In principle you could create a whole separate tokenizer and tree builder. But obviously that would probably be a poor choice for a native implementation compared to adding some flags and variable behavior. I'm not even necessarily claiming that all the above properties are advantages, I just wanted to show that there need not be a multi-escapting problem nor necessarily scary complicated changes to the tokenizer states for <script>.

I think the biggest advantage to this kind of approach is that it can be polyfilled with full fidelity. But I am in no way wedded to this solution and I am intrigued at the mention of other approaches with this property. The others I know of (external source only, srcdoc like on iframe) seem clearly worse, but there might be other bigger ones.

>  
> (D) Can be implemented with near-identical behavior for XHTML, except that you'd need an XML fragment parser.
> 
> The downside is that nested templates don't parse the same as top-level templates.  

Indeed. That is in addition to the previously conceded downsides that the syntax is somewhat less congenial.

> Another issue is that you've also introduced the following security risk:
> 
> Today, the following line of JavaScript is safe to include in an inline script tag:
> 
> var x = "</+script><img onerror=alert(1)>";
> 
> Because that line does not contain "</script>", the string "alert(1)" will be treated as the contents of a string.  However, if that line is included in an inline script inside of a template, the modifications of to the parser above will mean that alert(1) will execute as JavaScript rather than being treated as a string, introducing an XSS vector.

I don't follow. Can you give a full example of how this would be included in a template and therefore be executed?


>  
> I hope this clarifies the proposal.
> 
> Notes:
> - Just because it's described this way doesn't mean it has to be implemented this way - implementations could do template parsing in a single pass with HTML parsing if desired. I wrote it this way mainly to demonstrate the desired properties/
> 
> I'm not sure how we'd be able to that without running multiple copies of the tokenizer state machine in parallel.  The tokenizer states for the template fragment parser aren't going to line up in any meaningful way with the top-level tokenizer's search for an appropriate end tag to escape from the script data states.

I'm pretty confident it's *possible* to do a one-pass version of this algorithm, but I am not sure if it is easy, or if it is desirable.

What I actually imagined (knowing much less about HTML parsing than you) was that you'd enter a different tokenizer state after encountering a <script template> than a <script>. But defining that state would be challenging.

Regards,
Maciej

Received on Thursday, 1 November 2012 13:34:25 UTC