Делает вывод JsonConvert.SerializeObject необходимо закодировать в представлении Razor?
Я использую библиотеку Newtonsoft для преобразования объектов C# в JSON. Это использование Newtonsoft.Json.JsonConvert.SerializeObject
secure, или необходима дополнительная кодировка? Если требуется дополнительная кодировка, что вы предлагаете?
вот как я использую его в представлении Razor:
<script type="text/javascript">
var jsModel = @Html.Raw(Newtonsoft.Json.JsonConvert.SerializeObject(Model))
</script>
5 ответов
вам, по крайней мере, нужно будет выполнить дополнительную кодировку символа " " в "\u003E". Последний раз, когда я проверял JSON.NET не кодировал эти символы строковыми литералами.
Я, вероятно, получу flak для этого, но способ, которым я бы это сделал, - это отобразить фиктивный элемент на странице:
<div id="the-div" data-json="@JsonConvert.SerializeObject(Model)" />
затем в Javascript извлеките data-json значение атрибута интернет-див элемент и JSON.parse
его. Преимущество этого заключается в том, что вам не нужно беспокоиться о том, какие символы требуют специального кодирования. The SerializeObject
метод гарантии что JSON blob хорошо сформирован, и @
оператор гарантии что любые оставшиеся символы, не являющиеся HTML-безопасными, оставшиеся от преобразования JSON, правильно экранируются перед помещением в атрибут HTML (если значение атрибута окружено двойными кавычками, как указано выше). Так что да, это немного уродливее, но эффективнее при полном закрытии целого класса уязвимостей.
используя @Html.Raw
в одиночку, как и вопрос, определенно опасно. Вот еще один способ безопасного вывода модели в <script></script>
теги. Я последовал примеру @Levi, чтобы зависеть от способностей браузера, а также функций безопасности 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>"
})
))");
следующим шагом было бы обернуть это в многоразовый метод расширения HtmlHelper.
Я сделал этот JsonConverter, который кодирует все строки с Microsoft Web Protection Library-library (он же AntiXSS-library) (http://wpl.codeplex.com/):
/// <summary>
/// To be used when you're going to output the json data within a script-element on a web page.
/// </summary>
public class JsonJavaScriptEncodeConverter : Newtonsoft.Json.JsonConverter
{
public override bool CanConvert(Type objectType)
{
return objectType == typeof(string);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
return reader.Value;
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
writer.WriteRawValue(Microsoft.Security.Application.Encoder.JavaScriptEncode((string)value, true));
}
}
использование:
<script type="text/javascript">
var jsModel = @Html.Raw(Newtonsoft.Json.JsonConvert.SerializeObject(Model, new JsonJavaScriptEncodeConverter()))
</script>
Я не думаю, что здесь обязательно небезопасно, но это зависит от данных. Если ваши данные были дезинфицированы, что всегда должно быть, если они пришли из внешнего источника, то вы, вероятно, в порядке. Тот факт, что он входит в объект javascript и не отображается как HTML, немного затемняет вещи, но все равно сводится к вашему уровню доверия с выводом данных.
думал сбросить строку кода или два на основе золотого ответа Торбьерна Ханссона:
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
}
и вот несколько примеров того, как его использовать (и когда его не использовать):
<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 " ' ' )"> 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>
надеюсь, что это помогает.