Search code examples
javascripthtmlasp.netencodinghtml-encode

Should I use both HtmlEncode and JavaScriptStringEncode if inside HTML <script> tag to create HtmlString from string?


My question is very similar to this one, but without the <% %> details.

Let's say I have the following code:

public static IHtmlString AddSomethingToWindow(string value) {
            var output = new StringBuilder();
            output.AppendLine("<script type='text/javascript'>");
            output.Append("window.something=\"" + value + "\";");
            output.Append("</script>");
            return new HtmlString(output.ToString());
}

Let's say value is coming from an untrusted source & could be anything.

To make RenderSomething method safe, do I need HttpUtility.HtmlEncode(HttpUtility.JavaScriptStringEncode(value)) or is just HttpUtility.JavaScriptStringEncode(value) sufficient? Or are both wrong?


Solution

  • I strongly believe, although I'm not 100% sure, that JavaScriptStringEncode is enough.

    (1) From HTML spec:

    The easiest and safest way to avoid the rather strange restrictions described in this section is to always escape an ASCII case-insensitive match for "<!--" as "\x3C!--", "<script" as "\x3Cscript", and "</script" as "\x3C/script"...

    (2) The core idea of this is supported by answers from other people 1 & 2, even though they may not be fully accurate or up to date with the spec comment above (from which the second linked answer is actually derived).

    (3) Looking at JavaScriptStringEncode, it seemingly replaces <, among other characters, which should satisfy (1).

    Screenshot of JavaScriptStringEncode implementation that makes a call to a method called CharRequiresJavaScriptEncoding for each character of the string and replaces such cases with their unicode character Screenshot of CharRequiresJavaScriptEncoding implementation which takes a character and checks whether it's, among other characters, an opening angle bracket

    From these 3 points, I think one can conclude that calling JavaScriptStringEncode is enough, since the code inside script doesn't need to be HTML encoded, it just needs to escape <!--, <script, and </script (case-insensitively), which JavaScriptStringEncode by escaping < (replacing it with its Unicode sequence).