Often, in ASP.NET
& JavaScript
apps it is required to pass the server-side model to client-side without AJAX
requests. For that, the server-side model is converted to JSON
and puts somewhere in JavaScript
. You know that. Let’s have a quiz.
What the following ASP.NET MVC Razor
view will show?
@using Newtonsoft.Json
@{
var serverModel = new[]
{
new {Name = "<script>alert(1);</script>"},
new {Name = "<script>alert(2);</script>"}
};
var json = JsonConvert.SerializeObject(serverModel);
}
<html>
<body>
<pre id="content"></pre>
<script>
var clientModel = @Html.Raw(json);
var content = document.getElementById("content");
content.innerText = clientModel.map(e => e.Name).join("\n");
</script>
</body>
</html>
Or just pure HTML
/JavaScript
page. What about this?
<html>
<body>
<pre id="content"></pre>
<script>
var clientModel = [
{"Name":"<script>alert(1);</script>"},
{"Name":"<script>alert(2);</script>"}
];
var content = document.getElementById("content");
content.innerText = clientModel.map(e => e.Name).join("\n");
</script>
</body>
</html>
Oops, it gives 2
in the alert window! Hello, cross-site scripting. It is not obvious at all, at least for me. Moreover, I have seen such a pattern of passing the server-side model to client-side quite often. For example: link #1, link #2, link #3.
It turned out that browser’s HTML
parser doesn’t care whether </script>
tag is inside a string or not, most probably it is due to optimization. Stack Overflow proof.
How can we fix such vulnerability? I will give you a few options.
Use StringEscapeHandling.EscapeHtml
setting
Newtonsoft.Json
has a built-in feature to escape <
>
characters by passing StringEscapeHandling.EscapeHtml
as a setting during serialization. Stack Overflow answer.
var json = JsonConvert.SerializeObject(serverModel, new JsonSerializerSettings
{
StringEscapeHandling = StringEscapeHandling.EscapeHtml
});
Encode JSON
via HttpUtility.JavaScriptStringEncode
.NET
has a built-in feature HttpUtility.JavaScriptStringEncode
to encode JSON
but it returns a string so JSON.parse
is required. Stack Overflow answer.
var clientModel = JSON.parse("@Html.Raw(HttpUtility.JavaScriptStringEncode(json))");
Serialize via Json.Encode
.NET
has a built-in Json.Encode
it serializes and encodes at the same time. However, be careful JavaScriptSerializer
is used instead of Newtonsoft.Json
, so some unexpected behavior can take place.
Welcome, I reproduced this vulnerability in Gaev.Blog.Examples.ScriptInString. You can also find there proposed fixes.