Sanitizing Input with JsonConvert.SerializeObject in MVC4?

ぃ、小莉子 提交于 2019-12-05 17:43:14
nemesv

The problems is that you cannot have a closing </script> tag inside a JavaScript string literal because the browser interprets it as then end of the script block. See also: Script tag in JavaScript string

There is no builtin function in Asp.Net what could handle it on the server side you before outputting your generated script you need to replace the </script> to something else:

<script type="text/javascript">
    $(document).ready(ko.applyBindings(new MyProfileVm(@Html.Raw(
        JsonConvert.SerializeObject(Model, 
            new JsonSerializerSettings() { 
                 ContractResolver = new CamelCasePropertyNamesContractResolver() 
        }).Replace("</script>", "</scripttag>")
    ))));
</script>

Of course if you will need this in multiple place you can move this logic into a helper/extension method, like:

public static class JavaScriptExtensions
{
    public static string SerializeAndEscapeScriptTags(this object model)
    {
        return JsonConvert.SerializeObject(model,
            new JsonSerializerSettings()
                {
                    ContractResolver = new CamelCasePropertyNamesContractResolver()
                }).Replace("</script>", "</scripttag>");
    }
}

And use it with:

@using YourExtensionMethodsNamespace

<script type="text/javascript">
        $(document).ready(ko.applyBindings(new MyProfileVm(@Html.Raw(
            Model.SerializeAndEscapeScriptTags()))));
</script>

And on the JavaScript side in your Knockout viewmodel you need to replace back the </script> tag before the usage:

var MyProfileVm = function(data) {
   //...
   this.aboutMe = ko.observable(
     // you need  `"</scr"+ "ipt>"` because of the above mentioned problem.
   data.aboutMe.replace(/<\/scripttag>/g, "</scr"+ "ipt>"));
}

Of course you can also create a helper function for this, like:

function fixScriptTags(data) {
    for(var prop in data) {
        if (typeof(data[prop]) == "string") {
            data[prop] = data[prop].replace(/<\/scripttag>/g, "</scr"+ "ipt>");
        }
        //todo check for complex property values and call fixScriptTags recursively
    } 
    return data;
}

And use it with:

ko.applyBindings(new ViewModel(fixScriptTags(data)));

Demo JSFiddle.

I've had a similar problem, it came from using knockout.js to get input from a <textarea> just like you did. Everything was fine on the "create" part, but once I put the data back into an action via @Html.Raw(...), it turned out to contain linefeed and carriage-return characters that broke the json string. So I added something like this:

// Regex to replace all unescaped (single) backslashes in a string
private static Regex _regex = new Regex(@"(?<!\\)\\(?!\\)", RegexOptions.Compiled);

(I know it doesn't handle "\\\", but that doesn't appear from knockout)

Then I build my anonymous classes and do this:

var coJson = JsonHelper.Serialize(co);
var coJsonEsc = _regex.Replace(coJson, @"\\")

Maybe this can help you. I found it by breaking in the razor view and looking at the strings. This problem also appears with unesacped tabs (\t) and possibly other escape sequences.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!