159

I'm trying to write an object as JSON to my Asp.Net MVC View using Razor, like so:

<script type="text/javascript">
  var potentialAttendees = @Json.Encode(Model.PotentialAttendees);
</script>

The problem is that in the output the JSON is encoded, and my browser doesn't like it. For example:

<script type="text/javascript">
    var potentialAttendees = [{&quot;Name&quot;:&quot;Samuel Jack&quot;},];
</script>

How do I get Razor to emit unencoded JSON?

Community
  • 1
  • 1
Samuel Jack
  • 32,712
  • 16
  • 118
  • 155

3 Answers3

200

You do:

@Html.Raw(Json.Encode(Model.PotentialAttendees))

In releases earlier than Beta 2 you did it like:

@(new HtmlString(Json.Encode(Model.PotentialAttendees)))
Samuel Jack
  • 32,712
  • 16
  • 118
  • 155
Lorenzo
  • 29,081
  • 49
  • 125
  • 222
  • 3
    What can i do if i want some encoded text in my objects properties? \,{\"UrlPart\":\"TjcolklFX5c\",\"Title\":\"When Mama Isn\u0027t Home\"},{\" For example. This will break beacause js thinks the ' is escaping the native string decalration of var a = ' ' same goes for " ". anny idea ? – SomeRandomName Feb 20 '15 at 15:59
  • @SomeRandomName you can use `javascriptserializer` for that like `@Html.Raw(javascriptSerializerObjecct.Serialize(myObject))` – vikscool Apr 21 '17 at 07:30
  • We are in 2017, using MVC 5 and this answer is still perfect! – Gabriel Espinoza May 29 '17 at 19:23
  • This answer is the only one that works perfectly. Thanks! – Jean-Paul Feb 04 '18 at 11:37
47

Newtonsoft's JsonConvert.SerializeObject does not behave the same as Json.Encode and doing what @david-k-egghead suggests opens you up to XSS attacks.

Drop this code into a Razor view to see that using Json.Encode is safe, and that Newtonsoft can be made safe in the JavaScript context but is not without some extra work.

<script>
    var jsonEncodePotentialAttendees = @Html.Raw(Json.Encode(
        new[] { new { Name = "Samuel Jack</script><script>alert('jsonEncodePotentialAttendees failed XSS test')</script>" } }
    ));
    alert('jsonEncodePotentialAttendees passed XSS test: ' + jsonEncodePotentialAttendees[0].Name);
</script>
<script>
    var safeNewtonsoftPotentialAttendees = JSON.parse(@Html.Raw(HttpUtility.JavaScriptStringEncode(JsonConvert.SerializeObject(
        new[] { new { Name = "Samuel Jack</script><script>alert('safeNewtonsoftPotentialAttendees failed XSS test')</script>" } }), addDoubleQuotes: true)));
    alert('safeNewtonsoftPotentialAttendees passed XSS test: ' + safeNewtonsoftPotentialAttendees[0].Name);
</script>
<script>
    var unsafeNewtonsoftPotentialAttendees = @Html.Raw(JsonConvert.SerializeObject(
        new[] { new { Name = "Samuel Jack</script><script>alert('unsafeNewtonsoftPotentialAttendees failed XSS test')</script>" } }));
    alert('unsafeNewtonsoftPotentialAttendees passed XSS test: ' + unsafeNewtonsoftPotentialAttendees[0].Name);
</script>

See also:

Community
  • 1
  • 1
Jeremy Cook
  • 20,840
  • 9
  • 71
  • 77
  • Do you have any idea when they added Json.Encode? I wasn't aware there was actually a safe way to insert json on the page and I know I did alot of research on it in the past. – Chris Marisic Jul 07 '16 at 18:03
  • 1
    `Json.Encode` has been around as long as I can remember, but the downside is that it uses Microsoft's implementation that outputs non-standard dates (and may do other bothersome things). I use and encourage the use of Newtonsoft's `JsonConvert.SerializeObject` combined with proper escaping because it has better output. – Jeremy Cook Jul 08 '16 at 15:53
  • 2
    Glad I scrolled down. Immediately I saw the accepted answer, I hoped there was a safe way to do this. – frostymarvelous Jul 29 '16 at 11:13
  • The HttpUtility.JavaScriptStringEncode version also encodes the quote marks in the JSON, rendering it invalid if used directly in a script[type='application/json'], which is a pity. – Pete Kirkham Sep 28 '17 at 15:12
  • 1
    Note to future self: The one you want to use is this: @Html.Raw(Json.Encode( )) – Pangamma May 02 '18 at 23:44
  • Is there any way to make sure the Json.Encode handles reference loops properly? – Pangamma Aug 30 '18 at 17:11
  • @Pangamma I would suggest you use JsonConvert and pass JsonSerializerSettings with [ReferenceLoopHandling](https://www.newtonsoft.com/json/help/html/SerializationSettings.htm#ReferenceLoopHandling) handling set to the value that meets your needs. Not sure what you mean by "properly". Handling something "properly" varies from case to case. So you would need to be more specific about what isn't working and how you wish it would be working. – Jeremy Cook Aug 31 '18 at 20:13
  • Isn't this only unsafe if you can't trust the JSON you are inserting to the page? – crush Jan 22 '20 at 17:19
  • @crush there are two factors, one is trust but the other is malformed HTML. Proper encoding addresses both. Visit [this page](https://owasp.org/www-project-cheat-sheets/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html) and search for the word "context" to learn more. – Jeremy Cook Jan 23 '20 at 16:26
15

Using Newtonsoft

<script type="text/jscript">
  var potentialAttendees  = @(Html.Raw(Newtonsoft.Json.JsonConvert.SerializeObject(Model.PotentialAttendees)))
</script>
Ravi Ram
  • 24,078
  • 21
  • 82
  • 113
  • 1
    This is potentially vulnerable to XSS vulnerabilities which Json.Encode fixes, but you can override the `JsonSerializerSettings.StringEscapeHandling` to enable encoding. https://stackoverflow.com/a/50336590/6950124 – Kevin Secrist May 14 '18 at 18:45