Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/379.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/asp.net-mvc/17.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript JsonConvert.SerializeObject的输出是否需要在Razor视图中编码?_Javascript_Asp.net Mvc_Security_Razor - Fatal编程技术网

Javascript JsonConvert.SerializeObject的输出是否需要在Razor视图中编码?

Javascript JsonConvert.SerializeObject的输出是否需要在Razor视图中编码?,javascript,asp.net-mvc,security,razor,Javascript,Asp.net Mvc,Security,Razor,我使用Newtonsoft库将C#对象转换为JSON。这是对Newtonsoft.Json.JsonConvert.SerializeObject的安全使用,还是需要额外的编码?如果需要额外的编码,你有什么建议 以下是我如何在Razor视图中使用它: <script type="text/javascript"> var jsModel = @Html.Raw(Newtonsoft.Json.JsonConvert.SerializeObject(Model)) </s

我使用Newtonsoft库将C#对象转换为JSON。这是对
Newtonsoft.Json.JsonConvert.SerializeObject
的安全使用,还是需要额外的编码?如果需要额外的编码,你有什么建议

以下是我如何在Razor视图中使用它:

<script type="text/javascript">
    var jsModel = @Html.Raw(Newtonsoft.Json.JsonConvert.SerializeObject(Model))
</script>

var jsModel=@Html.Raw(Newtonsoft.Json.JsonConvert.SerializeObject(Model))

我不认为这里一定不安全,但这取决于数据。如果您的数据已经过清理(如果数据来自外部源,它总是应该进行清理),那么您可能就没事了。它进入一个javascript对象,并且没有呈现为HTML,这一事实使事情变得有点模糊,但它仍然取决于您对输出数据的信任程度。

您至少需要执行额外的编码,将“”字符编码为'\u003E'。上一次我检查JSON.NET没有将这些字符编码为字符串文字

我可能会因此受到指责,但我的做法是在页面上呈现一个虚拟元素:

<div id="the-div" data-json="@JsonConvert.SerializeObject(Model)" />


然后,在Javascript中,从div元素中提取数据json属性值并解析它。这样做的好处是,您不需要担心哪些字符需要特殊编码。
SerializeObject
方法保证JSON blob格式良好,
@
操作符保证在将JSON转换剩余的任何非HTML安全字符放入HTML属性之前正确转义(只要属性值被双引号包围,如上所述)因此,是的,它有点丑陋,但它可以有效地完全关闭整个类别的漏洞。

像问题一样单独使用
@Html.Raw
,这绝对是危险的。下面是另一种在
标记中安全输出模型的方法。我也遵循@Levi的示例,依赖于浏览器的功能l作为Microsoft的安全功能,并提出以下建议:

var jsModel = JSON.parse("@Html.Raw(HttpUtility.JavaScriptStringEncode(
    JsonConvert.SerializeObject(Model)
))");
我使用了以下非常简单的测试。如果我只使用问题中的
@Html.Raw
,则会出现“坏”警报。以这种方式包装,我有有效的JavaScript,警报不会出现

var jsModel = JSON.parse("@Html.Raw(HttpUtility.JavaScriptStringEncode(
    JsonConvert.SerializeObject(new {
        Test = "</script><script>var test = alert('Bad')</script>"
    })
))");
var jsModel=JSON.parse(“@Html.Raw(HttpUtility.JavaScriptStringEncode(
序列化对象(新的{
Test=“var Test=警报('Bad')”
})
))");

下一步是将其封装在可重用的HtmlHelper扩展方法中。

我制作了这个JsonConverter,它使用Microsoft Web保护库(又称AntiXSS库)对所有字符串进行编码():

//
///要在网页上的脚本元素中输出json数据时使用。
/// 
公共类JsonJavaScriptEncodeConverter:Newtonsoft.Json.JsonConverter
{
公共覆盖布尔CanConvert(类型objectType)
{
返回objectType==typeof(字符串);
}
公共重写对象ReadJson(JsonReader阅读器,类型objectType,对象existingValue,JsonSerializer序列化程序)
{
返回reader.Value;
}
公共重写void WriteJson(JsonWriter编写器、对象值、JsonSerializer序列化器)
{
WriteRawValue(Microsoft.Security.Application.Encoder.JavaScriptEncode((字符串)值,true));
}
}
用法:

<script type="text/javascript">
    var jsModel = @Html.Raw(Newtonsoft.Json.JsonConvert.SerializeObject(Model, new JsonJavaScriptEncodeConverter()))
</script>

var jsModel=@Html.Raw(Newtonsoft.Json.JsonConvert.SerializeObject(Model,新的JsonJavaScriptEncodeConverter()))

根据托尔比约恩·汉森的黄金答案,我想删除一两行代码:

public static class U
{
    private static readonly GeneralPurposeJsonJavaScriptEncodeConverter _generalEncoder = new GeneralPurposeJsonJavaScriptEncodeConverter();
    static public IHtmlString Js(this object obj) => new HtmlString(JsonConvert.SerializeObject(obj, _generalEncoder));

    private sealed class GeneralPurposeJsonJavaScriptEncodeConverter : JsonConverter //0
    {
        private static readonly Type TypeOfString = typeof(string);

        public override bool CanConvert(Type objectType) => objectType == TypeOfString;
        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) => reader.Value;
        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) => writer.WriteRawValue(Microsoft.Security.Application.Encoder.JavaScriptEncode((string) value, emitQuotes: true)); //1
    }
    //0 https://stackoverflow.com/a/28111588/863651   used when we need to burn raw json data directly inside a script element of our html like when we do when we use razor
    //1 note that the javascript encoder will leave nonenglish characters as they are and rightfully so   apparently the industry considers text in html attributes and inside
    //  html text blocks to be a battery for potential xss exploits and this is why the antixsslib applies html encoding on nonenglish characters there but not here   one
    //  could make the claim that using unicode escape sequences here for nonenglish characters could be potentionally useful if the clients receiving the server html response
    //  do not support utf8   however in our time and age clients that dont support utf8 are rarer than hens teeth so theres no point going this direction either
}
下面是一些关于如何使用它(以及何时不使用它)的示例:


@SomeStringWhichRightContaineQuotes@*此处不需要使用.Js()*@
@*这里不需要使用.Js()*@
@*这里也不需要使用.Js()-这将自动运行*@
@*但是请注意,我们必须将字符串用单引号括起来*@
正文
它将按预期工作*@
最后但并非最不重要的是:

<script type="text/javascript">
    someJsController.Init({
        @* containerSelector: “#@(containerId.Js())”,  ← wrong  dont do this *@

        containerSelector: “#” + @(containerId.Js()),  @* ← correct  *@
        containerSelector2: @($"#{container2Id}".Js()),  @* ← even better do this for readability *@

        simpleString: @(Model.FilterCode.Js()), @* all these will serialize correctly *@
        someArray: @(Model.ColumnsNames.Js()), @* by simply calling the .js() method *@
        someNumeric: @(Model.SelectedId.Js()),
        complexCsharpObject: @(Model.complexCsharpObject.Js())
    });
</script>

someJsController.Init({
@*containerSelector:“#@(containerId.Js())”,← 错了,不要这样做*@
containerSelector:“#”+@(containerId.Js()),@*← 正确的*@
containerSelector2:@($“{container2Id}.Js()),@*← 为了可读性,最好这样做*@
simpleString:@(Model.FilterCode.Js()),@*所有这些都将正确序列化*@
someArray:@(Model.ColumnsNames.Js()),@*只需调用.Js()方法*@
someNumeric:@(Model.SelectedId.Js()),
ComplexSharpObject:@(Model.complexSharpObject.Js())
});

希望这能有所帮助。

数据不是来自受信任的来源。换一种方式来看,即使它来自受信任的来源,我仍然希望确保输出的任何内容都是有效的对象。不应该
@Html.attributencode(JsonConvert.SerializeObject(Model))
是否使用?'@Html.AttributeEncode'将对输出进行双重编码。'@'运算符本身就是必需的,因为它被设计用于生成对常规Html和Html属性都安全的输出。
@
(例如
Html.encode
)在这种情况下,单独使用似乎是可以接受的,但是
Html.AttributeEncode
也是可以接受的。我不认为它会对输出进行双重编码,但当然我想知道我是否错了。请参阅
@input
转换为
响应。Write(HtmlEncode(input))
。因此
@Html.AttributeEncode(input)
将转换为
Response.Write(HtmlEncode(HtmlAttributeEncode(输入)))
,这导致了双重编码。我们明确设计了
@
以确保常规HTML和HTML属性都是安全的,这样开发人员就不必担心HtmlEncode和HTMLATTRIBUTENCODE之间的差异。啊,你是对的,我假设
HTMLATTRIBUTENCODE
返回了
MvcHtmlString<span>
            @someStringWhichMightContainQuotes @* no need to use .Js() here *@
</span>

@* no need to use .Js() here *@
<input value="@someStringWhichMightContainQuotes" />

@* no need to use .Js() here either - this will work as intended automagically *@
@* notice however that we have to wrap the string in single-quotes *@
<button   onclick="Foobar( '@("abc  \"  '  ")'  )"> Text </button>

@* The resulting markup will be:
            <button onclick="Foobar(  'abc &quot; &#39; '  )"> Text </button>
Which will work as intended *@
<script type="text/javascript">
    someJsController.Init({
        @* containerSelector: “#@(containerId.Js())”,  ← wrong  dont do this *@

        containerSelector: “#” + @(containerId.Js()),  @* ← correct  *@
        containerSelector2: @($"#{container2Id}".Js()),  @* ← even better do this for readability *@

        simpleString: @(Model.FilterCode.Js()), @* all these will serialize correctly *@
        someArray: @(Model.ColumnsNames.Js()), @* by simply calling the .js() method *@
        someNumeric: @(Model.SelectedId.Js()),
        complexCsharpObject: @(Model.complexCsharpObject.Js())
    });
</script>