-
Notifications
You must be signed in to change notification settings - Fork 31
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
Naming of the innerHTML setter (e.g., setInnerHTML
.)
#100
Comments
If we need a new function to set I think it might be valuable for the platform in the future to distinguish whether assertThisIsALiteral`i am not dynamic` If the innerHTML setter signature uses the option bag, it makes it hard to add support for the above - it would have to use something like: el.setInnerHTML(ignoreMe, {literal: assertThisIsALiteral`the actual value`}) One option to allow for this extension would be to have dedicated setters instead of one, e.g.: el.setInnerHTML.sanitized(dirty, {sanitizer})
el.setInnerHTML.literal`i am constant`
el.setInnerHTML.unsafe("please block me, CSP!") That way the argument list, and its options can be freely chosen by the appropriate setter variant. That way it's also probably easier to reason about the code statically. // cc @mikewest |
I like @shhnjk's point, that an innerHTML-alike name might confuse people who remember that "innerhtml is dangerous". @otherdaniel, and Mario (@cure53) talked about it and in lack of a better term arrived at content, which is already an existing property name for a So, how about |
That assumes that the sanitizer will be the only API ever allowed to set the content. How about |
what is a bare setContentSanitized or setSanitizedContent are also terribly long and boring.. |
It's only required for the setter that's plumbed to the sanitizer (and there are already requests for other setters e.g. whatwg/dom#912). I suspect there would be setters that have a combination of required and optional arguments - the most ergonomic way of supporting that, I think, is to make each of those variants a separate function with its own signature. We could group them under
That would work, I think. I have a slight preference towards precise API surface rather than a generic endpoint that can do many things depending on arguments. Predictability is boring, and yet we want the API to intuitively describe what it's doing, no? |
Isn't |
e.setHTML("test");
e.innerHTML="test"; I'm not sure we need to make it clear it's sanitized. All new parser APIs should be safe-by-default from now on I think. I'm also not sure I understand @koto's concern. It seems that requiring literals would either be a higher-level switch, a change to the API, or perhaps something you enforce through an option? Any of these would be compatible as far as I can tell. But I'd love to learn more as it does seem like something that would be good to get right from the start. |
the function needs to accept a sanitizer instance @annevk. The sanitizer is not bound to some per-global or per-document state. |
Of course, but that's an optional argument right? I'm not sure how that relates to my comment. |
I don't think that can be an optional argument. The point of the API is to give developers an easy-to-use setter without any built-in footguns. A function that gives hard security guarantees if the 2nd parameter is present and guaranteed insecurity if it's missing doesn't really meet that goal. The safe setter - whatever it ends up being called - should either be safe, or fail. |
Why can the sanitizer not have safe defaults? What exactly do you need to configure there for it to work? |
As far as I can tell, the most viable option for the platform APIs to distinguish literals from other values, is if the function accepting the value is a tag template function - which ties our hands w.r.t. to the function signature (it's el.setHTML(input, sanitizer)
// and, in the future
el.setHTML.literal`this_is_not_injected_for_sure` I think what's important is that the new setter (and all variants of it) is strictly more secure than |
The sanitizer has safe defaults. Was your intent that I personally would prefer an explicit instance over an implied one, as I find that less surprising. On the plus side, Element.SetHTML with built-in Sanitizer might increase usage of the Sanitizer. |
Yeah, I was expecting the second argument to merely be some options that have safe defaults, but can be overridden if you need more control over sanitization. I don't think we want everyone that has to parse a string to have to explicitly consider and configure a sanitizer. @koto given that we cannot distinguish that type from a string it's still unclear to me what that means. And even once we can distinguish it, what it would mean then. |
We can, from within the tag template function. The first argument is a frozen array of strings, and the whole array is in the Realm's
I think it would be huge for combating injections, if platform was able to distinguish literals from dynamic values, as the first ones are by definition non-user-controllable without a very specific kind of server-side injection. |
Regarding the naming,
To give more high-level description, Web Platform currently doesn't have a way to say developers are assigning static string or dynamic string.
AND
Are both string assignment (even though one is static and one is dynamic). What @koto suggested is to give a primitive to developers, where the platform can understand the notion of static string assignment. This primitive is important in the platform, because if we know something is static, it is safe to append without sanitization. BTW, |
Very specific, but very common. (Though if anyone has actual stats for Reflected XSS (I couldn't find any with a cursory search) that would be great). |
I realize we're diverging from the thread, but I highly doubt that reflections inside template strings inside a script are common. That would require something like this on the server side: <script>
foo = `bar<?php echo $_GET['xss'] ?>`
</script> Additionally, this would only be risky if the injection was not able to escape from the template, but was able to inject HTML, which seems quire rare. Regardless, the best the platform can do to combat this, and other server-side XSSes is CSP I don't want this issue to become about the literals, I only want to highlight that other setters might be worthy creating, so let's not just assume that sanitizer-bound setter is the only one to exist, so perhaps ( |
I understand that you might want a function that can be easily used with a tagged template string, @koto, and I think it's really worth discussing but let's please move that to a different issue. Are there any objections to |
Yes. For the reasons outlined, I prefer |
Looking at the #102, |
Mainly that it's shorter and can then be more easily advertised (possibly together with raw) as the replacement for |
I see, those are valid advantages. The disadvantage I see is a slight surprise factor - it doesn't just "set" HTML, it's modifying it. Another variant might be With the option for |
Some thoughts:
|
As of now, the only other option that is currently discussed is a parsing option whether to parse a declarative shadow DOM (whatwg/dom#912). If that parsing option is to become a thing, we can't implement our parsing invocation without taking options for the parser. That said, it would be a bit surprising if someone wants to setHTML according to the declarative shadow DOM use-case only and find their string to be sanitized? I mean, I like an always-secure setter, but I can also see this as very confusing :| |
Thanks, I hadn't seen that. If that indeed becomes a thing, then I presume any parsing Sanitizer function would want the option, in which case it'd be a natural fit for the Sanitizer config. (See also #45.)
IMHO, that speaks for explicit-ness in some form. Either by having a required (not optional) Sanitizer argument, or by referencing it in the name. (That said, I acknowledge this is a matter of taste, and other people will see it differently. I can live with it either way.) |
It could be reasonable to support
|
Hmm. If I take Anne's requirements, and my (admittedly rather sketchy) understanding of WebIDL's overloading rules, then we should have two overloads
(Merging those by making Sanitizer optional would make it difficult to define future overloads. Although I take it that's a tricky topic.) The single param version would be whatever the platform considers to be sensible default behaviour; I assume with default sanitization with whatever current or future defaults we pick. Future overloads could offer any combination of additional arguments or different types, since a (non-nullable) interface is distinguishable from pretty much anything else. |
If we are going to this route, I would prefer to have the default option as literal. That is:
This way, the latter object can have room for extension in the future. |
|
+1 to The tag functions have a specific signature interface mixin InnerHTML {
[CEReactions] attribute [LegacyNullToEmptyString] DOMString innerHTML;
undefined setHTML(object|DOMString innerHTML, optional any... arguments);
};
undefined setHTML(object|DOMString innerHTML, optional object options); would work, since we're not expecting any interpolation anyway. |
This issue is merely about the name. The template thing was discussed in #102 ;) |
I don't like the naming of
setInnerHTML
. In the security industry, we said so much about avoid usinginnerHTML
, that library like React use the name called dangerouslySetInnerHTML. It's super hard to tell people now that "Hey!setInnerHTML
is safe!". At the very least, it's confusing for developers.setHTML
(orsetSanitizedHTML
) sounds better.Originally posted by @shhnjk in #42 (comment)
The text was updated successfully, but these errors were encountered: