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

Allowing the script tag to be used as a data block (<script type="application/json">…</script>) would be helpful #292

Closed
umajho opened this issue Nov 8, 2023 · 8 comments

Comments

@umajho
Copy link

umajho commented Nov 8, 2023

For example:

<script id="foo" type="application/json">
  { bar }
</script>

The “Code-only components” approach mentioned here is very uncomfortable for me to use, since:

  • I need to implement the sanitization of attribute values (like the value of id) by myself, and
  • I need to implement the sanitization of the json data that might be user generated (to prevent things like </script>) by myself.

It would be very helpful if the library itself provide this functionality.

@joerdav
Copy link
Collaborator

joerdav commented Nov 9, 2023

Thanks for raising the issue.

Can you expand on this a bit please? What is bar in this case?

How can we allow raw javascript to be interpolated in to templates whilst protecting from XSS attacks?

@umajho
Copy link
Author

umajho commented Nov 10, 2023

Thanks for raising the issue.

Can you expand on this a bit please? What is bar in this case?

How can we allow raw javascript to be interpolated in to templates whilst protecting from XSS attacks?

Thanks for the response.

bar is a json string, for example, it can be constructed by:

barData, err := json.Marshal(barValue)
if err != nil { /* … */ }
bar := string(barData)

And you may read bar in JavaScript by:

const barJSON = document.getElementById("foo").textContent;
const bar = JSON.parse(barJSON);

As long as the json string is carefully escaped in the <script type="application/json"> tag, using it in JavaScript should be as safe(/unsafe) as using json data responded from AJAX.

Since my knowledge on this is very limited, I will just leave what I found on stack exchange:
https://security.stackexchange.com/questions/236881

@joerdav
Copy link
Collaborator

joerdav commented Nov 10, 2023

Okay! I think I understand your scenario now. You are looking to place JSON in a script tag.

I think a code-only component would work for your use case here, with validation for id:

templ Template() {
	@JsonScript("foo", bar)
}

func JsonScript(id, rawJson string) templ.Component {
	return templ.ComponentFunc(func(ctx context.Context, w io.Writer) error {
		_, err := fmt.Fprintf(w, `<script id="%s" type="application/json">%s</script>`, 
			templ.EscapeString(id), 
			rawJson)
		return err
	})
}

Although, as you mention, if bar is user provided it could cause some issues, you may want to opt for rendering the JSON within the component.

templ Template() {
	@JsonScript("foo", struct{Some string}{"json"})
}

func JsonScript(id string, obj any) templ.Component {
	return templ.ComponentFunc(func(ctx context.Context, w io.Writer) error {
		if _, err := fmt.Fprintf(w, `<script id="%s" type="application/json">`, templ.EscapeString(id)); err != nil {
			return err
		}
		if err := json.NewEncoder(w).Encode(obj); err != nil {
			return err
		}
		if _, err := w.Write([]byte("</script>")); err != nil {
			return err
		}
		return nil
	})
}

If neither of these solutions fit your needs, then there may be a change needed here to accomodate.

@umajho
Copy link
Author

umajho commented Nov 10, 2023

These solutions definitely fit my need. Thank you.


In the future, would it be possible to make it easier to embed data in script tags with types that definitely won't make the content be processed by the browser? (like application/json)
It is a little counter-intuitive that one can easily use a div (<div style="display: none">{bar}</div>), which is not designed for holding data, to hold data; but requires some workarounds to use a script[type="application/json"] to hold data.

@JustDerb
Copy link
Contributor

This might be solved now that #285 has been merged. I'd be interested in knowing if that update doesn't fix things 👀

@joerdav
Copy link
Collaborator

joerdav commented Nov 14, 2023

I'm not sure it does, here @umajho is talking about a script tag containing JSON rather than a JS script. But it sounds like it's resolved:

These solutions definitely fit my need. Thank you.

@JustDerb
Copy link
Contributor

Ahh, yep! Read this issue a little too fast 😅

@joerdav
Copy link
Collaborator

joerdav commented Jan 30, 2024

Closing, as resolved.

@joerdav joerdav closed this as completed Jan 30, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants