ASP.Net json POST 的 RequestValidation 以匹配表单 RequestValidation
ASP.Net RequestValidation for json POST to match Form RequestValidation
我希望能够以与表单验证 ("application/x-www-form-urlencoded") 一致的方式对内容类型 "application/json" 执行 RequestValidation。
我读过 https://msdn.microsoft.com/en-us/library/system.web.util.requestvalidator(v=vs.110).aspx,但没有太大帮助。
我正在考虑尝试实现一个自定义请求验证器来替换默认 System.Web.Util.RequestValidator。
我也看过https://msdn.microsoft.com/en-us/library/system.web.util.requestvalidator(v=vs.110).aspx
如果我不能让输入得到一致的验证,我可能会删除将 json 发送到控制器并强制所有内容通过表单的功能 - 不理想,因为我想要一些方法来接受json.
我已经对输出进行了编码(在可能的情况下),但我仍然希望通过验证输入来进行深度防御,并且理想情况下对于表单和 json。
不幸的是,许多关于此的 MSDN 文档已经严重过时,现在已无关紧要。
我正在使用 .net 4.6.1 作为参考。
以这种方式尝试和验证请求是否明智?
最后我实现了自定义 ModelBinder...这是阅读本文的组合 https://weblogs.asp.net/imranbaloch/security-issue-in-asp-net-mvc3-jsonvalueproviderfactory and this https://gist.github.com/jamescrowley/b8c0c006e7b00e28cbbf
它修改了请求的来源 (RequestValidationSource.Form) 使其看起来像一个表单,因此可以在同一管道中对其进行验证。
public class JsonValidatingModelBinder : DefaultModelBinder
{
public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
var result = base.BindModel(controllerContext, bindingContext);
if (!IsJsonRequest(controllerContext))
{
return result;
}
if (!bindingContext.ModelMetadata.RequestValidationEnabled)
{
return result;
}
if (result != null)
{
EnsureRequestFieldIsValid(controllerContext, result);
}
return result;
}
static void EnsureRequestFieldIsValid(ControllerContext controllerContext, object result)
{
int index;
// abusing RequestValidationSource enum
if (!RequestValidator.Current.InvokeIsValidRequestString(
controllerContext.HttpContext.ApplicationInstance.Context,
result.ToString(), RequestValidationSource.Form, null, out index))
{
throw new HttpRequestValidationException(
"A potentially dangerous value was detected from the client ");
}
}
static bool IsJsonRequest(ControllerContext controllerContext)
{
return controllerContext.HttpContext.Request.ContentType.StartsWith("application/json", StringComparison.OrdinalIgnoreCase);
}
并在 Global.asax...
protected void Application_Start()
{
System.Web.Mvc.ModelBinders.Binders.DefaultBinder = new JsonValidatingModelBinder();
}
我希望能够以与表单验证 ("application/x-www-form-urlencoded") 一致的方式对内容类型 "application/json" 执行 RequestValidation。
我读过 https://msdn.microsoft.com/en-us/library/system.web.util.requestvalidator(v=vs.110).aspx,但没有太大帮助。
我正在考虑尝试实现一个自定义请求验证器来替换默认 System.Web.Util.RequestValidator。
我也看过https://msdn.microsoft.com/en-us/library/system.web.util.requestvalidator(v=vs.110).aspx
如果我不能让输入得到一致的验证,我可能会删除将 json 发送到控制器并强制所有内容通过表单的功能 - 不理想,因为我想要一些方法来接受json.
我已经对输出进行了编码(在可能的情况下),但我仍然希望通过验证输入来进行深度防御,并且理想情况下对于表单和 json。
不幸的是,许多关于此的 MSDN 文档已经严重过时,现在已无关紧要。
我正在使用 .net 4.6.1 作为参考。
以这种方式尝试和验证请求是否明智?
最后我实现了自定义 ModelBinder...这是阅读本文的组合 https://weblogs.asp.net/imranbaloch/security-issue-in-asp-net-mvc3-jsonvalueproviderfactory and this https://gist.github.com/jamescrowley/b8c0c006e7b00e28cbbf
它修改了请求的来源 (RequestValidationSource.Form) 使其看起来像一个表单,因此可以在同一管道中对其进行验证。
public class JsonValidatingModelBinder : DefaultModelBinder
{
public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
var result = base.BindModel(controllerContext, bindingContext);
if (!IsJsonRequest(controllerContext))
{
return result;
}
if (!bindingContext.ModelMetadata.RequestValidationEnabled)
{
return result;
}
if (result != null)
{
EnsureRequestFieldIsValid(controllerContext, result);
}
return result;
}
static void EnsureRequestFieldIsValid(ControllerContext controllerContext, object result)
{
int index;
// abusing RequestValidationSource enum
if (!RequestValidator.Current.InvokeIsValidRequestString(
controllerContext.HttpContext.ApplicationInstance.Context,
result.ToString(), RequestValidationSource.Form, null, out index))
{
throw new HttpRequestValidationException(
"A potentially dangerous value was detected from the client ");
}
}
static bool IsJsonRequest(ControllerContext controllerContext)
{
return controllerContext.HttpContext.Request.ContentType.StartsWith("application/json", StringComparison.OrdinalIgnoreCase);
}
并在 Global.asax...
protected void Application_Start()
{
System.Web.Mvc.ModelBinders.Binders.DefaultBinder = new JsonValidatingModelBinder();
}