将 HTML 字符串传递给我的控制器操作方法
Passing HTML string to my controller action method
我正在使用富文本编辑器键入格式化文本,如下所示:
我可以获得 HTML 格式的文本,如下所示:
<p>This is my rich HTML Text</p>
现在我想将此 HTML 格式的文本传递给我的控制器,我的控制器会将文本放入电子邮件中并将其发送给接收者。
问题是 HTML 字符串被认为是不安全的,因此为了将它传递给我的控制器,我需要将 [ValidateInput(false)]
属性添加到我的 Action 方法中,如下所示:
[ValidateInput(false)] // <-- not able to hit the action method without this
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<JsonResult> Contact(string message)
{
if (!HttpContext.User.Identity.IsAuthenticated)
{
return Json(new { Authorize = "false" });
}
// email message to receiver
}
这是联系控制器的Ajax方法:
$('#contactBtn').click(function () {
var form = $('#__AjaxAntiForgeryForm');
var token = $('input[name="__RequestVerificationToken"]', form).val();
var message = quill.root.innerHTML; // <-- HTML formatted message
$.ajax({
url: "/Communication/Contact",
data: { __RequestVerificationToken: token, message: message },
dataType: 'json',
type: "POST"
});
});
所以上面的代码有效,但我不确定这样做是否正确?上面的代码有什么安全问题吗?我需要对 HTML 进行任何编码吗?
实际上 ValidateInput
属性与 XSS (Cross Site Security
) 问题有关。
XSS(跨站点安全) 是一种安全攻击,攻击者在进行数据输入时注入恶意代码。此代码可以是 javascript、vbscript 或任何其他脚本代码。一旦代码被注入最终用户的浏览器。此代码可以 运行 并获得对 cookie、会话、本地文件等的访问权限。
现在好消息是 XSS 在 ASP.NET MVC 中默认被阻止。因此,如果有人尝试使用 post JavaScript 或 HTML 代码输入,他会出现以下错误。
A potentially dangerous Request.Form value was detected from the client.....
但在现实生活中有些情况下 HTML 必须被允许,例如 HTML 编辑器。因此,对于这些场景,我们用 ValidateInput
属性装饰我们的操作方法,如下所示:
[ValidateInput(false)]
public async Task<JsonResult> Contact(string message)
{
}
但是这样做有问题。我们允许 HTML 和脚本完成可能很危险的操作。假设我们 posting 的表单有五个输入文本字段,现在所有五个文本字段都可以包含 HTML 和脚本。
改为 Microsoft article 建议:
For ASP.NET MVC 3 or greater applications, when you need to post HTML back to your model, don’t use ValidateInput(false) to turn off Request Validation. Simply add [AllowHtml] to your model property, like so:
public class BlogEntry
{
public int UserId {get;set;}
[AllowHtml]
public string BlogText {get;set;}
}
所以底线是 ValidateInput
允许脚本和 HTML 在整个操作级别上 post 编辑,而 AllowHTML
在更精细的级别上。
在 action 方法上使用 [ValidateInput(false)]
不是一个好方法,因为可能还有其他输入参数未经过验证...如果我们传入型号...
对于这种情况,我们可以按照 this tutorial:
中的说明进行操作
我的解决方案基于上面的教程,除了我在模型绑定器中添加了清理逻辑,这意味着我们允许 HTML 输入,但使用 HTMLSanitizer 来清理输入。
定义了自定义模型活页夹:
public class AllowHtmlBinder: IModelBinder
{
// use HtmlSanitizer to remove unsafe HTML/JS from input
private HtmlSanitizer _htmlSanitizer = new HtmlSanitizer();
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
var request = controllerContext.HttpContext.Request;
var name = bindingContext.ModelName;
var unvalidatedInputMessage = request.Unvalidated[name]; // get the unvalidated input
var sanitizedMessage = _htmlSanitizer.Sanitize(unvalidatedInputMessage); // removed script or any XSS thread from user input
return sanitizedMessage;
}
}
并将其用于特定参数:
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<JsonResult> Contact([ModelBinder(typeof(AllowHtmlBinder))] string message)
{
if (!HttpContext.User.Identity.IsAuthenticated)
{
return Json(new { Authorize = "false" });
}
// email message to receiver
}
我正在使用富文本编辑器键入格式化文本,如下所示:
我可以获得 HTML 格式的文本,如下所示:
<p>This is my rich HTML Text</p>
现在我想将此 HTML 格式的文本传递给我的控制器,我的控制器会将文本放入电子邮件中并将其发送给接收者。
问题是 HTML 字符串被认为是不安全的,因此为了将它传递给我的控制器,我需要将 [ValidateInput(false)]
属性添加到我的 Action 方法中,如下所示:
[ValidateInput(false)] // <-- not able to hit the action method without this
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<JsonResult> Contact(string message)
{
if (!HttpContext.User.Identity.IsAuthenticated)
{
return Json(new { Authorize = "false" });
}
// email message to receiver
}
这是联系控制器的Ajax方法:
$('#contactBtn').click(function () {
var form = $('#__AjaxAntiForgeryForm');
var token = $('input[name="__RequestVerificationToken"]', form).val();
var message = quill.root.innerHTML; // <-- HTML formatted message
$.ajax({
url: "/Communication/Contact",
data: { __RequestVerificationToken: token, message: message },
dataType: 'json',
type: "POST"
});
});
所以上面的代码有效,但我不确定这样做是否正确?上面的代码有什么安全问题吗?我需要对 HTML 进行任何编码吗?
实际上 ValidateInput
属性与 XSS (Cross Site Security
) 问题有关。
XSS(跨站点安全) 是一种安全攻击,攻击者在进行数据输入时注入恶意代码。此代码可以是 javascript、vbscript 或任何其他脚本代码。一旦代码被注入最终用户的浏览器。此代码可以 运行 并获得对 cookie、会话、本地文件等的访问权限。
现在好消息是 XSS 在 ASP.NET MVC 中默认被阻止。因此,如果有人尝试使用 post JavaScript 或 HTML 代码输入,他会出现以下错误。
A potentially dangerous Request.Form value was detected from the client.....
但在现实生活中有些情况下 HTML 必须被允许,例如 HTML 编辑器。因此,对于这些场景,我们用 ValidateInput
属性装饰我们的操作方法,如下所示:
[ValidateInput(false)]
public async Task<JsonResult> Contact(string message)
{
}
但是这样做有问题。我们允许 HTML 和脚本完成可能很危险的操作。假设我们 posting 的表单有五个输入文本字段,现在所有五个文本字段都可以包含 HTML 和脚本。
改为 Microsoft article 建议:
For ASP.NET MVC 3 or greater applications, when you need to post HTML back to your model, don’t use ValidateInput(false) to turn off Request Validation. Simply add [AllowHtml] to your model property, like so:
public class BlogEntry
{
public int UserId {get;set;}
[AllowHtml]
public string BlogText {get;set;}
}
所以底线是 ValidateInput
允许脚本和 HTML 在整个操作级别上 post 编辑,而 AllowHTML
在更精细的级别上。
在 action 方法上使用 [ValidateInput(false)]
不是一个好方法,因为可能还有其他输入参数未经过验证...如果我们传入型号...
对于这种情况,我们可以按照 this tutorial:
中的说明进行操作我的解决方案基于上面的教程,除了我在模型绑定器中添加了清理逻辑,这意味着我们允许 HTML 输入,但使用 HTMLSanitizer 来清理输入。
定义了自定义模型活页夹:
public class AllowHtmlBinder: IModelBinder
{
// use HtmlSanitizer to remove unsafe HTML/JS from input
private HtmlSanitizer _htmlSanitizer = new HtmlSanitizer();
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
var request = controllerContext.HttpContext.Request;
var name = bindingContext.ModelName;
var unvalidatedInputMessage = request.Unvalidated[name]; // get the unvalidated input
var sanitizedMessage = _htmlSanitizer.Sanitize(unvalidatedInputMessage); // removed script or any XSS thread from user input
return sanitizedMessage;
}
}
并将其用于特定参数:
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<JsonResult> Contact([ModelBinder(typeof(AllowHtmlBinder))] string message)
{
if (!HttpContext.User.Identity.IsAuthenticated)
{
return Json(new { Authorize = "false" });
}
// email message to receiver
}