Render HTML-safe JSON strings, especially for use in <script> tags#483
Render HTML-safe JSON strings, especially for use in <script> tags#483lambda-fairy merged 5 commits intolambda-fairy:mainfrom
<script> tags#483Conversation
lambda-fairy
left a comment
There was a problem hiding this comment.
Thanks!
I haven't really thought about context-aware escaping yet, but this looks like a reasonable first step. Let's land it first and let it inform what to do next.
| /// Writes a string fragment to the specified writer. | ||
| /// | ||
| /// It replaces `<`, `>`, and `&` characters with `\u003c`, `\u003e`, and | ||
| /// `\u0026` Unicode escape sequences respectively. |
There was a problem hiding this comment.
Technically this should also include \u2028 and \u2029, to cover browsers that don't implement ES2019.
https://github.com/tc39/proposal-json-superset
Though I'm ok with ignoring this problem for now, given that we haven't decided on a policy w.r.t. legacy browsers yet.
|
|
||
| let mut offset = 0; | ||
| for (index, byte) in fragment.bytes().enumerate() { | ||
| if matches!(byte, b'<' | b'>' | b'&') { |
There was a problem hiding this comment.
For a future PR we can consider using Memchr3 for this (and the other escaping routines in this library).
| //! [advice-whatwg]: | ||
| //! https://html.spec.whatwg.org/multipage/scripting.html#restrictions-for-contents-of-script-elements | ||
| //! [advice-json-ld]: | ||
| //! https://www.w3.org/TR/json-ld/#restrictions-for-contents-of-json-ld-script-elements |
There was a problem hiding this comment.
Thanks for the detailed write-up here.
It might be worth also mentioning prototype pollution attacks (objects with keys named __proto__ or constructor). Embedding JSON with such keys won't cause immediate problems, but could reveal security issues if JavaScript code uses the parsed result naively.
[Presently there's no issue for this, though #181 might be closest. I use this with Maud in a private codebase of my own, and I thought it could be more widely useful. I also wanted to expose my approach to the light to check if it does actually make sense.]
Reproduced from
maud/src/json.rs:TryRendertrait, say, that would allow for fallible renderers. Alternatively, I think theexpect(...)call could remain in theimpl Render for serde_json::ValuebecauseValueshould be almost/entirely guaranteed to be valid JSON. TheJsonwrapper could be removed; just ask callers to useserde_json::to_valuethemselves.There are also a few things I fixed in passing, but I can extract those to a separate PR if necessary.