【问题标题】:Sanitizing Input with JsonConvert.SerializeObject in MVC4?在 MVC4 中使用 JsonConvert.SerializeObject 清理输入?
【发布时间】:2013-11-02 22:56:51
【问题描述】:

长话短说,我正在尝试对 JsonConvert.SerializeObject 的输出进行清理,而无需修改已保存数据的内容。

我正在开发一个在视图中具有以下标记的应用:

                 <textarea data-bind="value: aboutMe"></textarea>

如果我保存以下文本,我会遇到问题:

                 <script type="text/javascript">alert("hey")</script>

我在 FF 中遇到的错误:

违规渲染文本的相关部分:

$(document).ready(ko.applyBindings(new MyProfileVm({"profileUsername":"admin","username":"Admin","aboutMe":"alert(\"hey\")","title":"这是一个 简短的自我介绍! :)","thumbnail":"https://i.imgur.com/H1HYxU9.jpg","locationZip":"22182","locationName":"维也纳, 弗吉尼亚州”

最后 - 在我的观点的底部:

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

在这里,我将从 MVC 控制器获得的模型传递到 js ViewModel 中,以进行剔除以映射到可观察的数据。原始编码似乎是问题所在,但我不确定如何处理它。

明确地说,我正在从服务器获取数据,并将其输出到客户端,这破坏了 JSON/KO 组合。

【问题讨论】:

    标签: asp.net-mvc asp.net-mvc-4 knockout.js json.net


    【解决方案1】:

    问题是您不能在 JavaScript 字符串文字中包含结束 &lt;/script&gt; 标记,因为浏览器将其解释为脚本块的 then 结尾。另见:Script tag in JavaScript string

    在输出生成的脚本之前,Asp.Net 中没有内置函数可以在服务器端处理它,您需要将 &lt;/script&gt; 替换为其他内容:

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

    当然,如果您在多个地方都需要这个,您可以将此逻辑移动到辅助/扩展方法中,例如:

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

    并将其用于:

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

    在您的 Knockout 视图模型中的 JavaScript 端,您需要在使用前替换回 &lt;/script&gt; 标记:

    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>"));
    }
    

    当然你也可以为此创建一个辅助函数,比如:

    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;
    }
    

    并将其用于:

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

    演示JSFiddle.

    【讨论】:

    • @SB2055 我已经添加了一些示例,但是我更喜欢在 javascript 端一个一个替换,因为这样我会明确知道除了脚本标签之外我可以在哪个字段中。
    【解决方案2】:

    我遇到了类似的问题,它来自使用 knockout.js 从 &lt;textarea&gt; 获取输入,就像您所做的那样。 “创建”部分一切正常,但是一旦我通过@Html.Raw(...) 将数据放回操作中,结果发现它包含破坏 json 字符串的换行符和回车符。 所以我添加了这样的内容:

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

    (我知道它不处理“\\\”,但这不会出现在淘汰赛中)

    然后我构建我的匿名类并执行此操作:

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

    也许这可以帮助你。我通过打破剃刀视图并查看琴弦找到了它。 未转义的制表符 (\t) 和可能的其他转义序列也会出现此问题。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-04-29
      • 1970-01-01
      • 2018-11-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-02-16
      • 1970-01-01
      相关资源
      最近更新 更多