2

我有一个允许用户编辑电子邮件模板的应用程序。电子邮件模板使用 HTML,因此客户端将 HTML 发送到控制器。我正在使用 Jodit HTML 编辑器 ( https://xdsoft.net/jodit/ ) 作为消息正文,因此用户不必自己了解 HTML。我可以发布表单并且控制器接受请求,因为视图模型装饰有适当的 [AllowHtml] 属性;的确,ModelState.IsValid是真的。数据返回给客户端时发生错误;控制器不返回 json 对象,而是返回错误。

问题是,如何防止 asp.net 在返回时将此标记为危险?

请注意,此应用程序处理 PII,因此不验证请求不是一种选择。

这是错误(添加完整的错误以防有人发现有帮助):

“/ReallyAwesomeApp”应用程序中的服务器错误。

从客户端检测到具有潜在危险的 Request.Form 值(messagetext="<font color="#000000...")。

说明: ASP.NET 在请求中检测到具有潜在危险的数据,因为它可能包含 HTML 标记或脚本。这些数据可能表示试图破坏您的应用程序的安全性,例如跨站点脚本攻击。如果这种类型的输入适合您的应用程序,您可以在网页中包含代码以明确允许它。有关详细信息,请参阅 http://go.microsoft.com/fwlink/?LinkID=212874

异常详细信息: System.Web.HttpRequestValidationException:从客户端检测到潜在危险的 Request.Form 值(messagetext="<font color="#000000...")。

源错误:

在执行当前 Web 请求期间生成了未处理的异常。可以使用下面的异常堆栈跟踪来识别有关异常起源和位置的信息。

堆栈跟踪:

[HttpRequestValidationException (0x80004005):从客户端检测到潜在危险的 Request.Form 值 (messagetext="<font color="#000000...")。] System.Web.HttpRequest.ValidateString(String value, String collectionKey, RequestValidationSource requestCollection) +322
System.Web.<>c__DisplayClass280_0.b__0(String key, String value) +18
System.Web.HttpValueCollection.EnsureKeyValidated(String key) +86
System.Web.HttpValueCollection.Get(String name) +17
System .Web.Caching.OutputCacheModule.CreateOutputCachedItemKey(字符串路径,HttpVerb 动词,HttpContext 上下文,CachedVary cachedVary)+694 System.Web.Caching.OutputCacheModule.CreateOutputCachedItemKey(HttpContext 上下文,CachedVary cachedVary)+56
System.Web.Caching.OutputCacheModule.OnLeave(Object source, EventArgs eventArgs) +1226
System.Web.SyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +200 System.Web.<>c__DisplayClass285_0.b__0() +24 System.Web.StepInvoker.Invoke(Action executionStep) +100
System.Web.<>c__DisplayClass4_0.b__0() +17
Microsoft.AspNet.TelemetryCorrelation.TelemetryCorrelationHttpModule.OnExecuteRequestStep(HttpContextBase context, Action step) +64
System.Web.<>c__DisplayClass284_0.b__0(Action nextStepAction) +54 System.Web.StepInvoker.Invoke(Action executionStep) +84 System.Web.<>c__DisplayClass4_0.b__0() +17 Microsoft.ApplicationInsights.Web.ApplicationInsightsHttpModule.OnExecuteRequestStep (HttpContextBase context, Action step) in E:\A_work\21\s\WEB\Src\Web\Web.Shared.Net\ApplicationInsightsHttpModule.cs:164 System.Web.<>c__DisplayClass284_0.b__0(Action nextStepAction) +54 System .Web.StepInvoker.Invoke(Action executionStep) +84
System.Web.HttpApplication.ExecuteStepImpl(IExecutionStep step) +100
System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +73

版本信息:Microsoft .NET Framework 版本:4.0.30319;ASP.NET 版本:4.8.4075.0

这是我的视图模型:

public class EmailTemplateViewModel
{
    public IEnumerable<SelectListItem> EmailTemplates { get; set; }

    public List<EmailAttachmentViewModel> EmailAttachments { get; set; } = new List<EmailAttachmentViewModel>();

    public string CreateUserIdentifier { get; set; }

    public int TemplateID { get; set; }

    [Display(Name = "Template Name")]
    public string TemplateName { get; set; }

    [Display(Name = "Email Subject")]
    public string EmailSubject { get; set; }

    [AllowHtml]
    [Display(Name = "Message Text")]
    public string MessageText { get; set; }
}

这是我的回归模型(在 SO 上找到这个小宝石):

public class JsonReturnModel<T>
{
    public List<ClientError> ClientErrors { get; internal set; } = new List<ClientError>();

    public T Data { get; internal set; }

    public bool LoggedIn { get; internal set; }

    public string Message { get; set; }

    public List<ServerError> ServerErrors { get; internal set; } = new List<ServerError>();

    public bool Success { get; internal set; }
}

这是我的控制器方法:

    [HttpPost]
    [ValidateAntiForgeryToken]
    public JsonResult EditEmailTemplate(EmailTemplateViewModel model)
    {
        RepositoryResult result = new RepositoryResult();
        JsonReturnModel<EmailTemplateViewModel> returnModel = new JsonReturnModel<EmailTemplateViewModel>();

        if (model == null)
        {
            returnModel.Success = false;
            returnModel.Message = "No data sent to server.";

            return Json(returnModel);
        }
        
        EmailTemplateModel newModel = null;
        result = DataManager.UpdateEmailTemplate(model.ToEmailTemplateModel());

        if (result.IsSuccessful)
        {
            newModel = (EmailTemplateModel)result.ResultingObject;
            returnModel.Data = newModel.ToEmailTemplateViewModel();
        }
        
        returnModel.Success = result.IsSuccessful;
        returnModel.Message = result.Message;
        
        return Json(returnModel);
    }

最后是通过 JQuery 调用的 Ajax:

$('#save-btn').on('click', function (event) {
    var rawHtml = $('#message-editor').html();
    $('#MessageText').val(ESCM.joditEditor.value);

    $.ajax({
        type: "post",
        url: ESCM.EmailPostUrl,
        data: $("form").serialize(), 
        async: false,
        success: function (data) {
            if (data.IsSuccessful || data.Success) {
                $('#email-template-editor').click();
                $('#TemplateID').val(data.Data.TemplateID);
                $('#TemplateID').change();
            }
            DisplayMessage(data);
        },
        error: function (errorData) {
            console.debug(errorData);
        }
    });
});
4

0 回答 0