-
Notifications
You must be signed in to change notification settings - Fork 17.7k
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
html/template: refuse to parse complex JS template literals #60055
Comments
Presumably the idea is that this would allow detecting the end of a Consider these: let a = `${
// this is evil };-)
expression + goes + here
}`;
let b = `${ /* this is equally evil };-) */ foo + 3 }`;
let c = `${/[^}]*/.exec(input)[0]}`; Preventing misinterpretation in these cases would require blocklisting |
I think the suggested implementation would be more complex than simply looking for the next We would transition from We would probably also need a new state variable, similar to For instance, an incredibly basic interpretation of the parser state would be:
|
I'm not sure I understand. First you mention bailing out when encountering one of a specific set of special characters ( But now you're saying you'd still do "proper" handling of JavaScript inside placeholders when no bailout happens, and then use Why would the parser bail out on |
Oh bah, sorry, I managed to copy everything from my draft except the last paragraph which actually explained what I meant 🤦. Most things we already consider "complex" have their own states, quoted strings, regexp, etc, so we can immediately fail on those transitions (perhaps allowing the comment states?). Javascript objects (and any other brace delimited syntax) on the other hand don't, so we'd need to look for when we hit a character than would cause a change into jsCtxObject, and fail (a more ambitious project would be to continue parsing here, and attempt to actually properly support nesting literals, complex template syntax, etc. It is perhaps worthwhile at least exploring how feasible this is, but I suspect it's a hole that appears shallow, but immediately drops a thousand feet). In the above example then when we hit the first |
This definition of complex seems fine. I do think it's important to keep the simple cases working (passing through), even if we can't substitute into them ourselves. |
This proposal has been added to the active column of the proposals project |
Based on the discussion above, this proposal seems like a likely accept. |
No change in consensus, so accepted. 🎉 |
While I understand the importance of this change, it has introduced a limitation that doesn't appear to have an easy work around. If I want to assign a multi-line template to a JavaScript variable, is my only remaining option to create a function to transform newlines to ones compatible with '' and "" JavaScript strings (i.e, replace '\n' with '+' and '')? I relied on template literals to implement dynamic forms with Go templates, but am struggling to find an alternative solution. {{ define "date-row" }}
<td>{{ .Start }}</td>
<td>{{ .End }}
{{ end }} <table>
{{ range .Dates }}
{{ template "date-row" . }}
{{ end }}
</table> <script>
const dateRow = `{{ template "date-row" . }}`
const addDateRange = () => {
const row = document.createElement('tr');
row.innerHTML = dateRow;
const dates = document.getElementById('dates');
dates.appendChild(row);
};
</script> |
Revisiting this, I spent some time prototyping a slightly more complex state tracking change in http://go.dev/cl/507995, this is essentially the "more ambitious project" described in #60055 (comment). This prototype implements string interpolation expression depth tracking, and switches between the template string state and top-level JS state when entering and exiting template expressions (i.e. Unless someone spots a particularly egregious error I've made in the implementation, I think this presents us with three possible paths to go down:
|
With http://go.dev/cl/507995 this template parses incorrectly: <script>
var foo = `x` + "${ {{.}}";
</script> Passing in <script>
var foo = `x` + "${ "; alert(1); //"";
</script> |
I really appreciate the efforts to improve the implementation. Does the Go team have any recommendations for the use case where a template with actions needs to be stored as a multi-line JavaScript string? |
@dwrz you could use a script data block: <script type="application/x-template" id="date-row-template">
{{ template "date-row" . }}
</script>
<script>
const dateRow = document.getElementById('date-row-template').innerHTML;
const addDateRange = () => {
const row = document.createElement('tr');
row.innerHTML = dateRow;
const dates = document.getElementById('dates');
dates.appendChild(row);
};
</script> |
@jupenur 🤦 there was a silly bug where state wasn't properly reset, should be working as intended now, let me know if you can see any other edge cases. |
@rolandshoemaker <script>
var foo = `${ (_ => { return "x" })() + "${ {{.}}" }`;
</script> ...with the input <script>
var foo = `${ (_ => { return "x" })() + "${ " + alert(1) + "" }`;
</script> |
Ah right, we need to track brace depth across JS contexts. I feel like this is slowly draining my life force... |
Alternative in #61619. |
Forking from #9200.
Our minimal JS state machine inside of the template parser is limited enough that we cannot reasonably understand the semantics of JS template literal syntax. Rather than attempting to bodge a interpreter for nested literals, i.e. as suggested in https://go.dev/cl/484075, we propose instead to simply refuse to parse complex literals, with the justification that we cannot reasonably determine the safety of these literals.
In terms of defining "complex", we would bail if we saw any special character (
`,",',$,{,}
) after encountering`${
. For example this would prevent parsing templates containing`${"asd"}`
,`${`${...}`}`
,`${let a = {};}`
, etc, while still supporting the majority of JS template use cases (including multi-line strings, and basic template actions, etc).cc @golang/security
The text was updated successfully, but these errors were encountered: