"От клиента обнаружено потенциально опасное значение Request.Form" при возврате JSON клиенту
У меня есть приложение, которое позволяет пользователю редактировать шаблоны писем. В шаблонах электронной почты используется HTML, поэтому клиент отправляет HTML контроллеру. Я использую HTML-редактор Jodit (https://xdsoft.net/jodit/) для тела сообщения, поэтому пользователям не нужно знать HTML самим. Я могу опубликовать форму, и контроллер принимает запрос, поскольку модель представления украшена соответствующим атрибутом [AllowHtml]; действительно,ModelState.IsValid
правда. Ошибка возникает, когда данные возвращаются клиенту; контроллер не возвращает объект json, а вместо этого возвращает ошибку.
Вопрос в том, как мне предотвратить пометку asp.net как опасной по возвращении?
Обратите внимание, что это приложение работает с PII, поэтому отказ от проверки запросов невозможен.
Вот ошибка (добавление полной ошибки на случай, если кто-то сочтет это полезным):
Ошибка сервера в приложении '/ReallyAwesomeApp'.
От клиента обнаружено потенциально опасное значение Request.Form (messagetext="
Описание: ASP.NET обнаружил данные в запросе, которые потенциально опасны, поскольку могут содержать разметку HTML или сценарий. Данные могут представлять собой попытку поставить под угрозу безопасность вашего приложения, например атаку межсайтового скриптинга. Если этот тип ввода подходит для вашего приложения, вы можете включить код на веб-страницу, чтобы явно разрешить его. Для получения дополнительной информации см. http://go.microsoft.com/fwlink/?LinkID=212874.
Сведения об исключении: System.Web.HttpRequestValidationException: от клиента обнаружено потенциально опасное значение Request.Form (messagetext="
Ошибка источника:
Во время выполнения текущего веб-запроса возникло необработанное исключение. Информацию о происхождении и местонахождении исключения можно определить с помощью трассировки стека исключений ниже.
Трассировки стека:
[HttpRequestValidationException (0x80004005): A potentially dangerous Request.Form value was detected from the client (messagetext="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(String path, HttpVerb verb, HttpContext context, CachedVary cachedVary) +694 System.Web.Caching.OutputCacheModule.CreateOutputCachedItemKey(HttpContext context, 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) +73Version Information: Microsoft.NET Framework Version:4.0.30319; ASP.NET Version:4.8.4075.0
Here is my view model:
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; }
}
Here's my return model (Found this little gem here on 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; }
}
Here's my Controller method:
[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);
}
And finally the Ajax that gets called via JQuery:
$('#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);
}
});
});