3

How do I properly encode JavaScript in the following context:

<html>
...
<script type="text/javascript">
var settings = @Html.PleaseEncode(settings.ToJson());
// ...
</script>
</html>

The values in my JSON objects are set by the application administrator, so I assume they need properly encoded -- both for HTML and JavaScript.

I'm using System.Web.Script.Serialization.JavaScriptSerializer to do the JSON encoding. It looks like JavaScriptSerializer does some encoding as it outputs the text <None> as \u003cNone\u003c, but I'm not sure how safe it is. Right now, I'm using @Html.Raw as it works given safe input. It generates the following:

var settings = {"UnselectedReason":"None Selected", /*...*/};

If I use @Html.Encode I then get:

var settings = {&amp;quot;UnselectedReason&amp;quot;:&amp;quot;None Selected&amp;quot;, /*...*/};

I've tried with and without AntiXSS but I see no difference either way.

Charles
  • 50,943
  • 13
  • 104
  • 142
Kaleb Pederson
  • 45,767
  • 19
  • 102
  • 147

5 Answers5

2

AntiXSS has JavaScriptEncode, but it's designed for individual items, rather than taking a whole set of, err, settings.

So if you passed in {"UnselectedReason":"None Selected", /.../} it'd eat the quotes and other things, which is probably not what you want. Instead what I'd do is in your ToJson I'd build the settings up with a string builder, something like

StringBuilder sb = new StringBuilder();
sb.Append("{");
foreach(KeyValuePair kv in mySettings)
{
    sb.Append("\"");
    sb.Append(Microsoft.Security.Application.Encoder.JavaScriptEncode(kv.Key, true);
    sb.Append(":");
    sb.Append(Microsoft.Security.Application.Encoder.JavaScriptEncode(kv.Value, true);
    sb.Append("\",");
}

string outputString = sb.ToString().TrimEnd(",") + "}";

return new HtmlString(outputString);

Note: Code is off the top of my head and hasn't been even typed into VS. It illustrates the principal and may well not compile!

blowdart
  • 55,577
  • 12
  • 114
  • 149
  • Hello @blowdart stranger : ) What attack vectors could you see here if a model (assuming just a model here) is Json'd that would require separate encoding? – Adam Tuliper Nov 28 '11 at 18:59
  • It depends where the model data comes from :) If it's settings in a config file that the admin sets then you should be ok. If it's settings that a user sets, for example, a colour or a sort order then you may run the risk of XSS or DOM injection ... – blowdart Nov 28 '11 at 19:11
  • ok, we're on the same page, thats what I meant below on the 'valid source'. – Adam Tuliper Nov 28 '11 at 20:12
1

If you are wanting to use the JS, why are you trying to encode it? If you have json, it should already be encoded. Since its JS, you shouldn't require html encoding on it either.

I don't believe you need to encode here, unless you can provide a case why and I'm just missing something?

With any valid javascript you could run the risk of injection, but since you know this is coming from some valid source (ie model) that is getting encoded the path is relatively safe to get the JSON.

Adam Tuliper
  • 29,982
  • 4
  • 53
  • 71
  • I'm not positive that I do or don't need to encode it, but I want to be sure that I've handled it appropriately. – Kaleb Pederson Nov 28 '11 at 18:52
  • In thinking about it more, I think my main concern was that the JSON might be encoded in a way that was fine for inclusion in a javascript file but not within a script tag. – Kaleb Pederson Nov 29 '11 at 19:41
1

It should be safe for direct output...

<script>//<![CDATA[<!--

var settings = @Html.Raw(settings.ToJson());

//-->]]></script

Though if you are really concerned... this assumes a modern browser or json2.js is included.

<script>

var settings = JSON.parse("@Html.Raw(Server.UrlEncode(settings.ToJson()))");

</script
Tracker1
  • 19,103
  • 12
  • 80
  • 106
  • I believe assigning a value from this returned content to inner html (ie $("#whatver").html(...)) would be a vector for an attack. – Adam Tuliper Jan 09 '12 at 19:56
  • @Adam, not sure what you are referring to... the whole purpose was to get server-side objects/content to the client-side. If you run un-checked user input to output, that is a separate issue. – Tracker1 Jan 24 '12 at 16:21
  • this was tagged (and mentioned) for antixss encoding, 'safe' was mentioned as well - hence there's an assumption the encoding here is to help prevent issues. 'unchecked' user input is such a generic term since there are a bazillion xss vectors that have gotten around some of the best 'checked' input filters. I want people to be safe in the solutions they implement, and I don't believe that's a separate issue when people copy/paste from SO all day long : ) If the solution potentially leaves someone open to XSS - it absolutely is relevant to this question. – Adam Tuliper Jan 24 '12 at 18:22
  • Assuming settings.ToJson() gives valid JSON, and JSON.parse is a valid parser, there's no XSS risk.. what you do with the encoded value is a different story. Also, nowhere in my post was it suggested to simply push any output to .html(output) ... the whole purpose was to deliver an object model to JS from the server to the client. – Tracker1 Jan 25 '12 at 19:58
  • true true, this post though is for additional information for people that come here, not to argue your point. I want people to be aware just because they get the data back 'seemingly safe' doesn't mean it is safe. Its safe in the single one line of code above, but caution what you do with it after. Again, not arguing your code, simply providing a warning. – Adam Tuliper Jan 26 '12 at 01:41
0

It will be safe. It won't destroy your markup.

Daniel A. White
  • 187,200
  • 47
  • 362
  • 445
0

If you are sure about what you want to do:

@Html.Raw(yourStringWithTheJSONcode)
Adilson de Almeida Jr
  • 2,761
  • 21
  • 37