Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Disallow non-templates as interpolations in Polymer.html #5023

Merged
merged 9 commits into from
Jan 31, 2018
Merged

Conversation

justinfagnani
Copy link
Contributor

This is to prevent XSS vulnerabilities from accidentally interpolating unsafe user-provided values into templates that would be interpreted as HTML.

With this change, the only values that can be used to construct templates are JS template literals and other HTML templates. We're not checking that HTML templates are created from Polymer.html, but if an app is letting user-controlled values into an HTML template as HTML, it already has an XSS.

cc @arthurevans and @katejeffreys for documenting this change.

Copy link
Member

@kevinpschaaf kevinpschaaf left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

* they are not intended as a replacement for Polymer data-binding.
* Templates can be composed by interpolating `HTMLTemplateElement`s in
* expressions in the JavaScript template literal. The nested template's
* `innerHTML` is inluced in the containing template.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'inluced' => 'included'

Copy link
Contributor

@sorvell sorvell left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's add a Polymer.htmlLiteral (bikeshed) so users have a way of getting a, say, imported string into a template.

Polymer.html`${Polymer.htmlLiteral(foo)}`

@justinfagnani
Copy link
Contributor Author

@sorvell sounds good.

I would want to offer this as another template tag so that it can only be used on literals, not on string variables, and it should disallow interpretations of plain strings.

For a function that can consume any string, I would want unsafe in the name, ie Polymer.unsafeHTML().

@justinfagnani
Copy link
Contributor Author

Given that 2.4 got tagged already, I think we should merge this as-is for a quick 2.4.1. We can always add more supported data types without breaking changes.

Copy link
Contributor

@TimvdLippe TimvdLippe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We talked about this in our meeting. I am okay with this change, given that the unsafeHTML function will be provided soon too.

P.S. build fails because you need to update the TypeScript types (this sadly also takes into account docs)

Allows composition of strings into html templates constructed with `Polymer.html`. This is useful for composing values into styles or other places where an html template would not compose.

```
const css = Polymer.htmlLiteral`background: red;`
Polymer.html`<style>:host { ${css} }</style>`
```

'use strict';

class PerfTester extends HTMLElement {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sorvell Was this class intended to be committed in this PR? If so, we need some docs on what it actually does and how we can use it (assuming you used it to measure the performance of the changes in this PR).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

argh, mistakenly committed; removing.

@@ -12,13 +12,31 @@
(function() {
'use strict';

class HTMLLiteral {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

docs

@@ -12,13 +12,31 @@
(function() {
'use strict';

class HTMLLiteral {
constructor(string) {
this.innerHTML = string;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wouldn't name this innerHTML, this isn't an element. I'd go with value

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was an attempt to write less code, since both types can return their string value via innerHTML; fair that it's a bit short-cutty.

*/
Polymer.htmlLiteral = function(strings, ...values) {
return new HTMLLiteral(values.reduce((acc, v, idx) =>
acc + literalValue(v) + strings[idx + 1], strings[0]));
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style nit: 4 space indent for wrapped expressions

if (value instanceof HTMLTemplateElement) {
return /** @type {!HTMLTemplateElement} */(value).innerHTML;
if (value instanceof HTMLTemplateElement || value instanceof HTMLLiteral) {
return /** @type {!HTMLTemplateElement | !HTMLLiteral} */(value).innerHTML;
} else {
throw new Error(`non-template value passed to Polymer.html: ${value}`);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this message should probably be updated to allow for htmlLiteral too

class HTMLLiteral {
constructor(string) {
this.innerHTML = string;
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider adding a toString() implementation with the literal value

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

* they are not intended as a replacement for Polymer data-binding.
* Templates can be composed by interpolating `HTMLTemplateElement`s in
* expressions in the JavaScript template literal. The nested template's
* `innerHTML` is included in the containing template.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should also include using htmlLiteral

@dfreedm dfreedm merged commit eeb7160 into master Jan 31, 2018
@dfreedm dfreedm deleted the html-tag branch January 31, 2018 01:04
@alchmy
Copy link

alchmy commented May 10, 2018

It seems like a pretty major problem to not be able to separate the HTML templates into separate files. This is absolutely key to being able to write modular code. I would naturally think it would be a developers choice if they wanted to add these arbitrary files. It sort of seems like it's just a way to keep code within a Polymer environment(I don't want to be confrontational, I do hope I'm wrong, as @justinfagnani says). Perhaps I haven't fully understood what's involved, but if I can't use arbitrary HTML templates, it's actually a deal breaker for me in terms of Polymer vs Vanilla WC.

The Components I was using stopped working a few days ago because I was importing html strings into my code and using them to build templates. The end user doesn't build web components, so is it fair to say that the restriction and the bubble wrap only affects developers who should be checking for XSS anyway ?

@miztroh-zz
Copy link

@alchmy: You may want to check out the HTML Modules discussion.

WICG/webcomponents#645

@alchmy
Copy link

alchmy commented May 10, 2018

Ok Thanks. I'll have a read through it.

@justinfagnani
Copy link
Contributor Author

@alchmy this isn't about not being able to break up templates, this is about not opening XSS vulnerabilities by blindly allowing user input to flow into privileged templates. You can compose templates, they just have be composed of values produced by the html tag.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants