-
Notifications
You must be signed in to change notification settings - Fork 12
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
Discussion: should we rework or remove unsafeHTML and unsafeSVG #216
Comments
Rationale for removing: After seven years and 10,000 commits across 12 engineers there are still only two places where we use
Both render calls are with Rationale for keeping: In order to hook into the DOM nodes generated by the template engine and its opaque lifecycle developers must be super familiar with
|
Current exemplary case: // ...
static template(html, { unsafe }) {
return ({ markdownResult }) => html`<div id="container">${unsafe(markdownResult)}</div>`;
}
// ... Would become (today): // ...
static template(html) {
return () => html`<div id="container"></div>`;
}
render() {
super.render();
const target = this.shadowRoot.getElementById('container');
target?.innerHTML = this.internal.markdownResult ?? '';
}
// ... Problem with this: Another method which is a bit more idiomatic (today): // ...
static get properties() {
return {
markdownResult: {
type: String,
compute: // ...
default: '',
observe: (host, value) => {
const target = host.shadowRoot.getElementById('container');
target?.innerHTML = value;
},
},
};
}
static template(html) {
return () => html`<div id="container"></div>`;
}
// ... Problem with this: developers need to know a lot about XElement property features and behavior. Also if In both cases developers need to juggle awareness of the property features and the template engine lifecycle and behavior (and have confidence that defying these abstractions is acceptable...) |
Maybe the way to go is that we allow for binding of // ...
static get properties() {
return {
markdownResult: {
type: String,
compute: // ...
},
markdownFragment: {
type: DocumentFragment,
input: ['markdownResult'],
compute: (markdownResult) => {
if (markdownResult) {
return new DocumentFragment().innerHTML = markdownResult;
}
},
},
};
}
static template(html) {
return ({ markdownFragment }) => html`<div id="container">${markdownFragment}</div>`;
}
// ... ... essentially what #207 is covering |
Opening an issue to cover past discussion on this topic — work has already begun in #213 — essentially:
unsafeHTML
andunsafeSVG
are necessary for developers who prefer to avoid imperative DOM manipulationunsafe
markup into an otherwise safe template is debatableunsafeSVG
has never been necessary (becauseunsafeHTML
can accomplish the same behavior when<svg></svg>
wraps the content)Thus if we remove
unsafe
entirely we will (potentially inadvertently) encourage unsafe behavior unknowingly (ifinnerHTML
were calledunsafeCrazyNativeFeature
we would perhaps feel differently). At the same time, the project philosophy states:Which could be interpreted as "stay out of my way, I know
innerHTML
is unsafe!" -or- "stay out of my way, I want to conveniently bindunsafe
markup in my declarative template!"The philosophy also states:
... and it could be argued that
unsafe
is not a "minimal" feature. Consider the following:This does not actually touch on the common concern when injecting unsafe HTML — the browser will not actually execute the code within the textarea element — instead it will display the HTML as a string. This snippet is exactly identical:
A more sinister example is:
If we had not used the
unsafe
directive, the template engine would simply print the markup as as string (by assigningdiv#example3.textContent = mySampleCode
— but this is not what we want. We actually want to allow the browser to expand the string and generate DOM (even if the string contains<script>/* malicious bad stuff */</script>
because presumably we are confident that other sanitization has already occurred upstream. (Note: do not make that assumption, it is unsafe! Always weigh the risks of what could go wrong and ensure there are other checks in place where it matters.)So the conundrum in a nutshell:
div#example4.innerHTML = '<script>/* malicious bad stuff */</script>'
Open for discussion...
The text was updated successfully, but these errors were encountered: