从客户端检测到潜在危险的Request. Form值

每当用户在我的Web应用程序的页面中发布包含<>的内容时,我都会抛出此异常。

我不想讨论抛出异常或崩溃整个Web应用程序的智能性,因为有人在输入框中输入了一个字符,但我正在寻找一种优雅的方式来处理这个问题。

捕捉例外并展示

发生错误,请返回并重新键入整个表单,但这次请不要使用<

对我来说不够专业。

禁用后验证(validateRequest="false")肯定会避免此错误,但它会使页面容易受到许多攻击。

理想情况下:当回发包含超文本标记语言限制字符时,表单集合中发布的值将自动被超文本标记语言编码。所以我的文本框的.Text属性将是something & lt; html & gt;

有没有办法我可以从处理程序中做到这一点?

1111280 次浏览

您可以超文本标记语言编码输入框内容,但不幸的是,这并不能阻止异常发生。根据我的经验,这是没有办法的,您必须禁用页面验证。这样做您就会说:“我会小心的,我保证。”

您应该使用Server. HtmlEncode方法来保护您的站点免受危险输入。

更多信息

我认为你从错误的角度攻击它,试图对所有发布的数据进行编码。

请注意,“<”也可以来自其他外部源,例如数据库字段、配置、文件、提要等。

此外,“<”本身并不危险。它只在特定的上下文中危险:当编写尚未编码为超文本标记语言输出的字符串时(因为XSS)。

在其他上下文中,不同的子字符串是危险的,例如,如果您将用户提供的URL写入链接,则子字符串“javascript:”可能是危险的。另一方面,在SQL查询中插入字符串时,单引号字符是危险的,但如果它是从表单提交或从数据库字段读取的名称的一部分,则完全安全。

底线是:您不能过滤危险字符的随机输入,因为任何字符在正确的情况下都可能是危险的。您应该在一些特定字符可能变得危险的点进行编码,因为它们交叉到具有特殊含义的不同子语言中。当您将字符串写入超文本标记语言时,您应该使用Server. HtmlEncode对超文本标记语言中具有特殊含义的字符进行编码。如果您将字符串传递给动态SQL语句,您应该编码不同的字符(或者更好的是,让框架通过使用准备好的语句等为您完成)。

你确定你的超文本标记语言-encode无处不在你传递字符串到超文本标记语言,然后设置ValidateRequest="false"<%@ Page ... %>指令在你的.aspx文件。

在. NET 4中,您可能需要做更多的事情。有时还需要将<httpRuntime requestValidationMode="2.0" />添加到web.config(参考)。

我想你可以在模块中完成;但这留下了一些问题;如果你想将输入保存到数据库怎么办?突然,因为你将编码数据保存到数据库,你最终会信任它的输入,这可能是一个坏主意。理想情况下,你将原始未编码数据存储在数据库中,每次都进行编码。

在每个页面级别禁用保护,然后每次编码是更好的选择。

而不是使用Server. HtmlEncode,您应该查看来自Microsoft ACE团队的更新、更完整的反XSS库

只要这些是只有"<"和">"(而不是双引号本身)字符,并且您在<输入值="这个"/>等上下文中使用它们,您就是安全的(而对于这一个,您当然会受到攻击)。这可能会简化您的情况,但对于任何更多的使用其他发布的解决方案之一。

如果您确实需要特殊字符(如><等),请禁用页面验证,然后确保在显示用户输入时,数据是超文本标记语言编码的。

页面验证存在安全漏洞,因此可以绕过它。此外,不应仅依赖页面验证。

见:http://web.archive.org/web/20080913071637/http://www.procheckup.com:80/PDFs/bypassing-dot-NET-ValidateRequest.pdf

如果你只是想告诉你的用户<和>不能使用,但是,你不希望整个表单被处理/发布回来(并丢失所有输入),你能不能简单地在字段周围放一个验证器来筛选这些(也许还有其他潜在的危险)字符?

请记住,一些. NET控件将自动对输出进行超文本标记语言编码。例如,在TextBox控件上设置. Text属性将自动对其进行编码。这具体意味着将<转换为&lt;,将>转换为&gt;,将&转换为&amp;。所以要小心这样做…

myTextBox.Text = Server.HtmlEncode(myStringFromDatabase); // Pseudo code

但是,HyperLink、Litals和Label的. Text属性不会对超文本标记语言进行编码,因此,如果要防止<script> window.location = "http://www.google.com"; </script>被输出到页面中并随后执行,必须将Server. HtmlEncode();环绕在这些属性上设置的任何内容。

做一些实验,看看什么被编码,什么没有。

如果您不想禁用ValidateRequest,您需要实现一个JavaScript函数以避免异常。这不是最好的选择,但它有效。

function AlphanumericValidation(evt){var charCode = (evt.charCode) ? evt.charCode : ((evt.keyCode) ? evt.keyCode :((evt.which) ? evt.which : 0));
// User type Enter keyif (charCode == 13){// Do something, set controls focus or do anythingreturn false;}
// User can not type non alphanumeric charactersif ( (charCode <  48)                     ||(charCode > 122)                     ||((charCode > 57) && (charCode < 65)) ||((charCode > 90) && (charCode < 97))){// Show a message or do somethingreturn false;}}

然后在后面的代码中,在PageLoad事件上,使用下一段代码将属性添加到您的控件:

Me.TextBox1.Attributes.Add("OnKeyPress", "return AlphanumericValidation(event);")

如果您使用的是ASP.NETMVC,则此错误有不同的解决方案:

C#示例:

[HttpPost, ValidateInput(false)]public ActionResult Edit(FormCollection collection){// ...}

Visual Basic示例:

<AcceptVerbs(HttpVerbs.Post), ValidateInput(False)> _Function Edit(ByVal collection As FormCollection) As ActionResult...End Function

您可以在我仍然想要验证但显示适当消息的Global.asax.中捕获该错误。

    void Application_Error(object sender, EventArgs e){Exception ex = Server.GetLastError();
if (ex is HttpRequestValidationException){Response.Clear();Response.StatusCode = 200;Response.Write(@"[html]");Response.End();}}

重定向到另一个页面似乎也是对异常的合理回应。

http://www.romsteady.net/blog/2007/06/how-to-catch-httprequestvalidationexcep.html

如果您使用的是. NET 4.0,请确保将其添加到<system.web>标记内的web.config文件中:

<httpRuntime requestValidationMode="2.0" />

在. NET 2.0中,请求验证仅应用于aspx请求。在. NET 4.0中,这被扩展为包括所有请求。您可以通过指定:

requestValidationMode="2.0"

您可以通过指定禁用请求验证完全

validateRequest="false"

以前的答案很棒,但是没有人说如何排除单个字段以验证超文本标记语言/JavaScript注入。我不知道以前的版本,但在MVC3 Beta中,你可以这样做:

[HttpPost, ValidateInput(true, Exclude = "YourFieldName")]public virtual ActionResult Edit(int id, FormCollection collection){...}

这仍然会验证除了被排除的字段之外的所有字段。这样做的好处是,您的验证属性仍然会验证该字段,但您不会得到“从客户端检测到潜在危险的Request. Form值”异常。

我用它来验证正则表达式。我创建了自己的ValidationAtite来查看正则表达式是否有效。由于正则表达式可以包含看起来像脚本的东西,我应用了上述代码-仍在检查正则表达式是否有效,但如果它包含脚本或超文本标记语言,则不检查。

在ASP.NETMVC中,您需要在web.config中设置Request estValidationMode="2.0"和validateRequest="false",并将ValidateInput属性应用于控制器操作:

<httpRuntime requestValidationMode="2.0"/>
<configuration><system.web><pages validateRequest="false" /></system.web></configuration>

[Post, ValidateInput(false)]public ActionResult Edit(string message) {...}

在ASP.NETMVC(从版本3开始)中,您可以将#0属性添加到模型的属性中。

它允许请求在模型绑定期间通过跳过属性的请求验证来包含超文本标记语言标记。

[AllowHtml]public string Description { get; set; }

似乎还没有人提到下面的内容,但它为我解决了这个问题。在有人说是之前,它是Visual Basic…讨厌。

<%@ Page Language="vb" AutoEventWireup="false" CodeBehind="Example.aspx.vb" Inherits="Example.Example" **ValidateRequest="false"** %>

我不知道是否有任何缺点,但对我来说,这是惊人的。

您还可以使用JavaScript的转义(字符串)函数来替换特殊字符。然后服务器端使用Server.URL解码(字符串)将其切换回来。

这样,您就不必关闭输入验证,其他程序员会更清楚地知道字符串可能具有超文本标记语言内容。

在web.config文件中,在标记中,插入属性为Request estValidationMode="2.0"的htpRuntime元素。还在页面元素中添加validateRequest="false"属性。

示例:

<configuration><system.web><httpRuntime requestValidationMode="2.0" /></system.web><pages validateRequest="false"></pages></configuration>

这里的其他解决方案很好,但是必须将[AllowHtml]应用于每个模型属性,特别是如果您在一个相当大的网站上有超过100个模型,这有点皇家的痛苦。

如果像我一样,你想把这个(IMHO非常毫无意义)特性从站点范围内关闭,你可以覆盖基本控制器中的Execute()方法(如果你还没有基本控制器,我建议你做一个,它们对于应用通用功能非常有用)。

    protected override void Execute(RequestContext requestContext){// Disable requestion validation (security) across the whole siteValidateRequest = false;base.Execute(requestContext);}

只要确保你是超文本标记语言编码的一切,从用户输入(它的默认行为ASP.NETMVC 3与剃刀,所以除非一些奇怪的原因你使用Html. Raw()你不应该需要这个功能。

在ASP.NET,您可以捕获异常并对其进行处理,例如显示友好消息或重定向到另一个页面……您也可以自己处理验证。

显示友好消息:

protected override void OnError(EventArgs e){base.OnError(e);var ex = Server.GetLastError().GetBaseException();if (ex is System.Web.HttpRequestValidationException){Response.Clear();Response.Write("Invalid characters."); //  Response.Write(HttpUtility.HtmlEncode(ex.Message));Response.StatusCode = 200;Response.End();}}

我最终在每次回发之前使用JavaScript来检查您不需要的字符,例如:

<asp:Button runat="server" ID="saveButton" Text="Save" CssClass="saveButton" OnClientClick="return checkFields()" />
function checkFields() {var tbs = new Array();tbs = document.getElementsByTagName("input");var isValid = true;for (i=0; i<tbs.length; i++) {if (tbs(i).type == 'text') {if (tbs(i).value.indexOf('<') != -1 || tbs(i).value.indexOf('>') != -1) {alert('<> symbols not allowed.');isValid = false;}}}return isValid;}

授予我的页面主要是数据输入,并且很少有元素进行回发,但至少它们的数据被保留。

我也犯了这个错误。

在我的例子中,用户在角色名称中输入了重音字符á(关于ASP.NET成员资格提供者)。

我将角色名称传递给一个方法以授予用户该角色,并且$.ajax post请求失败得很惨…

我这样做是为了解决问题:

而不是

data: { roleName: '@Model.RoleName', users: users }

做这个

data: { roleName: '@Html.Raw(@Model.RoleName)', users: users }

@Html.Raw成功了。

我得到的角色名称是超文本标记语言值roleName="Cadastro b&roleName25;s"。这个带有超文本标记语言实体&roleName25;的值被ASP.NETMVC阻止了。现在我得到了roleName参数值,它应该是:roleName="Cadastro Básico"ASP.NETMVC引擎不会再阻止请求了。

对于ASP.NET4.0,您可以通过将其全部放在<location>元素中来允许将标记作为特定页面而不是整个站点的输入。这将确保您所有其他页面都是安全的。您不需要将ValidateRequest="false"放在. aspx页面中。

<configuration>...<location path="MyFolder/.aspx"><system.web><pages validateRequest="false" /><httpRuntime requestValidationMode="2.0" /></system.web></location>...</configuration>

在web.config中控制它更安全,因为您可以在站点级别看到哪些页面允许标记作为输入。

您仍然需要在禁用请求验证的页面上以编程方式验证输入。

这些建议都不适合我。无论如何,我不想关闭整个网站的此功能,因为99%的时间我不希望我的用户在Web表单上放置超文本标记语言。我刚刚创建了自己的工作方法,因为我是唯一一个使用此特定应用程序的人。我将输入转换为后面代码中的超文本标记语言并将其插入我的数据库。

这个问题的答案很简单:

var varname = Request.Unvalidated["parameter_name"];

这将禁用对特定请求的验证。

你可以使用类似的东西:

var nvc = Request.Unvalidated().Form;

之后,nvc["yourKey"]应该工作。

另一种解决方案是:

protected void Application_Start(){...RequestValidator.Current = new MyRequestValidator();}
public class MyRequestValidator: RequestValidator{protected override bool IsValidRequestString(HttpContext context, string value, RequestValidationSource requestValidationSource, string collectionKey, out int validationFailureIndex){bool result = base.IsValidRequestString(context, value, requestValidationSource, collectionKey, out validationFailureIndex);
if (!result){// Write your validation hereif (requestValidationSource == RequestValidationSource.Form ||requestValidationSource == RequestValidationSource.QueryString)
return true; // Suppress error message}return result;}}

对于MVC,通过添加来忽略输入验证

[验证输入(假)]

在控制器中的每个操作之上。

正如我对Sel的回答的评论所指出的,这是我们对自定义请求验证器的扩展。

public class SkippableRequestValidator : RequestValidator{protected override bool IsValidRequestString(HttpContext context, string value, RequestValidationSource requestValidationSource, string collectionKey, out int validationFailureIndex){if (collectionKey != null && collectionKey.EndsWith("_NoValidation")){validationFailureIndex = 0;return true;}
return base.IsValidRequestString(context, value, requestValidationSource, collectionKey, out validationFailureIndex);}}

我找到了一个使用JavaScript对数据进行编码的解决方案,该解决方案在. NET中解码(并且不需要jQuery)。

  • 使文本框成为超文本标记语言元素(如文本区域)而不是ASP元素。
  • 添加隐藏字段。
  • 将以下JavaScript函数添加到您的标头中。

    函数boo_(){document.getElementById("HiddenField1");SourceText=document.getElementById("userbox");//来源文本targetText.value=转义(sourceText.inner文本);}

在你的文本区域中,包含一个调用boo()的onchange:

<textarea id="userbox"  onchange="boo();"></textarea>

最后,在. NET中,使用

string val = Server.UrlDecode(HiddenField1.Value);

我知道这是单向的——如果你需要双向的,你必须有创造力,但这提供了一个解决方案,如果你不能编辑web.config

这是我(MC9000)想出并通过jQuery使用的一个示例:

$(document).ready(function () {
$("#txtHTML").change(function () {var currentText = $("#txtHTML").text();currentText = escape(currentText); // Escapes the HTML including quotations, etc$("#hidHTML").val(currentText); // Set the hidden field});
// Intercept the postback$("#btnMyPostbackButton").click(function () {$("#txtHTML").val(""); // Clear the textarea before POSTing// If you don't clear it, it will give you// the error due to the HTML in the textarea.return true; // Post back});

});

以及标记:

<asp:HiddenField ID="hidHTML" runat="server" /><textarea id="txtHTML"></textarea><asp:Button ID="btnMyPostbackButton" runat="server" Text="Post Form" />

这很有效。如果黑客试图绕过JavaScript发布,他们只会看到错误。您也可以将所有这些编码的数据保存在数据库中,然后(在服务器端)取消转义,并在其他地方显示之前解析和检查攻击。

试试用

Server.Encode

Server.HtmlDecode发送和接收。

原因

默认情况下,ASP.NET验证可能导致跨站脚本攻击(XSS)和SQL注射的潜在不安全内容的所有输入控件。因此,它通过抛出上述异常来禁止此类内容。默认情况下,建议允许在每次回发时进行此检查。

解决方案

在许多情况下,您需要通过富文本框或富文本编辑器将超文本标记语言内容提交到您的页面。在这种情况下,您可以通过将@Page指令中的ValidateRequest标记设置为false来避免此异常。

<%@ Page Language="C#" AutoEventWireup="true" ValidateRequest = "false" %>

这将禁用已将ValidateRequest标志设置为false的页面的请求验证。如果要禁用此功能,请检查整个Web应用程序;您需要在web.config部分中将其设置为false

<pages validateRequest ="false" />

对于. NET 4.0或更高版本的框架,您还需要在部分中添加以下行以使上述工作。

<httpRuntime requestValidationMode = "2.0" />

就是这样。我希望这能帮助你摆脱上面的问题。

引用:ASP. Net错误:从客户端检测到潜在危险的Request. Form值

如果您使用的是Framework 4.0,则web.config中的条目(

<configuration><system.web><pages validateRequest="false" /></system.web></configuration>

如果您使用的是Framework 4.5,则web.config中的条目(请求ValidationMode="2.0")

<system.web><compilation debug="true" targetFramework="4.5" /><httpRuntime targetFramework="4.5" requestValidationMode="2.0"/></system.web>

如果你只想要单页,那么,在你的aspx文件中,你应该把第一行如下:

<%@ Page EnableEventValidation="false" %>

如果您已经有<%@Page之类的内容,那么只需添加其余=>EnableEventValidation="false"%>

我建议不要这样做。

您可以在自定义Model Binder中自动对超文本标记语言字段进行编码。我的解决方案有所不同,我将错误放在ModelState中并在字段附近显示错误消息。修改此代码以进行自动编码很容易

 public class AppModelBinder : DefaultModelBinder{protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType){try{return base.CreateModel(controllerContext, bindingContext, modelType);}catch (HttpRequestValidationException e){HandleHttpRequestValidationException(bindingContext, e);return null; // Encode here}}protected override object GetPropertyValue(ControllerContext controllerContext, ModelBindingContext bindingContext,PropertyDescriptor propertyDescriptor, IModelBinder propertyBinder){try{return base.GetPropertyValue(controllerContext, bindingContext, propertyDescriptor, propertyBinder);}catch (HttpRequestValidationException e){HandleHttpRequestValidationException(bindingContext, e);return null; // Encode here}}
protected void HandleHttpRequestValidationException(ModelBindingContext bindingContext, HttpRequestValidationException ex){var valueProviderCollection = bindingContext.ValueProvider as ValueProviderCollection;if (valueProviderCollection != null){ValueProviderResult valueProviderResult = valueProviderCollection.GetValue(bindingContext.ModelName, skipValidation: true);bindingContext.ModelState.SetModelValue(bindingContext.ModelName, valueProviderResult);}
string errorMessage = string.Format(CultureInfo.CurrentCulture, "{0} contains invalid symbols: <, &",bindingContext.ModelMetadata.DisplayName);
bindingContext.ModelState.AddModelError(bindingContext.ModelName, errorMessage);}}

Application_Start:

ModelBinders.Binders.DefaultBinder = new AppModelBinder();

请注意,它仅适用于表单字段。危险值未传递给控制器模型,但存储在ModelState中,并且可以在表单上重新显示错误消息。

URL中的危险字符可以这样处理:

private void Application_Error(object sender, EventArgs e){Exception exception = Server.GetLastError();HttpContext httpContext = HttpContext.Current;
HttpException httpException = exception as HttpException;if (httpException != null){RouteData routeData = new RouteData();routeData.Values.Add("controller", "Error");var httpCode = httpException.GetHttpCode();switch (httpCode){case (int)HttpStatusCode.BadRequest /* 400 */:if (httpException.Message.Contains("Request.Path")){httpContext.Response.Clear();RequestContext requestContext = new RequestContext(new HttpContextWrapper(Context), routeData);requestContext.RouteData.Values["action"] ="InvalidUrl";requestContext.RouteData.Values["controller"] ="Error";IControllerFactory factory = ControllerBuilder.Current.GetControllerFactory();IController controller = factory.CreateController(requestContext, "Error");controller.Execute(requestContext);httpContext.Server.ClearError();Response.StatusCode = (int)HttpStatusCode.BadRequest /* 400 */;}break;}}}

错误控制器:

public class ErrorController : Controller{public ActionResult InvalidUrl(){return View();}}

使用Server.HtmlEncode("yourtext");

对于那些仍然停留在Web表单上的人,我找到了以下解决方案,使您只能禁用一个字段的验证!(我讨厌在整个页面上禁用它。)

VB.NET:

Public Class UnvalidatedTextBoxInherits TextBoxProtected Overrides Function LoadPostData(postDataKey As String, postCollection As NameValueCollection) As BooleanReturn MyBase.LoadPostData(postDataKey, System.Web.HttpContext.Current.Request.Unvalidated.Form)End FunctionEnd Class

C#:

public class UnvalidatedTextBox : TextBox{protected override bool LoadPostData(string postDataKey, NameValueCollection postCollection){return base.LoadPostData(postDataKey, System.Web.HttpContext.Current.Request.Unvalidated.Form);}}

现在只需使用<prefix:UnvalidatedTextBox id="test" runat="server" />而不是<asp:TextBox,它应该允许所有字符(这非常适合密码字段!)

最后但同样重要的是,请注意ASP.NET数据绑定控件在数据绑定期间会自动编码值。这会更改ItemTemplate中包含的所有ASP.NET控件(TextBox、Label等)的默认行为。以下示例演示(ValidateRequest设置为false):

aspx

<%@ Page Language="C#" ValidateRequest="false" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="WebApplication17._Default" %> <html> <body><form runat="server"><asp:FormView ID="FormView1" runat="server" ItemType="WebApplication17.S" SelectMethod="FormView1_GetItem"><ItemTemplate><asp:TextBox ID="TextBox1" runat="server"></asp:TextBox><asp:Button ID="Button1" runat="server" Text="Button" OnClick="Button1_Click" /><asp:Label ID="Label1" runat="server" Text="<%#: Item.Text %>"></asp:Label><asp:TextBox ID="TextBox2" runat="server" Text="<%#: Item.Text %>"></asp:TextBox></ItemTemplate></asp:FormView></form>

背后的代码

public partial class _Default : Page{S s = new S();
protected void Button1_Click(object sender, EventArgs e){s.Text = ((TextBox)FormView1.FindControl("TextBox1")).Text;FormView1.DataBind();}
public S FormView1_GetItem(int? id){return s;}}
public class S{public string Text { get; set; }}
  1. 案例提交值:&#39;

Label1.Text值:&#39;

TextBox2.Text值:&amp;#39;

  1. 案例提交值:<script>alert('attack!');</script>

Label1.Text值:<script>alert('attack!');</script>

TextBox2.Text值:&lt;script&gt;alert(&#39;attack!&#39;);&lt;/script&gt;

在. Net 4.0及更高版本中,通常情况下,将以下设置放入system.web

<system.web><httpRuntime requestValidationMode="2.0" />

我看到有很多关于这个的文章……我没有看到提到这一点。自. NET Framework 4.5以来,这已经可用。NET Framework 4.5

控件的是否必填验证请求方式设置是一个很好的选择。这样,页面上的其他控件仍然受到保护。无需web.config更改

 protected void Page_Load(object sender, EventArgs e){txtMachKey.ValidateRequestMode = ValidateRequestMode.Disabled;}

一个解决方案

我不喜欢关闭后验证(validateRequest="false")。另一方面,仅仅因为无辜的用户碰巧键入<x或其他内容而导致应用程序崩溃是不可接受的。

因此,我编写了一个客户端javascript函数(xssCheckValidates)来进行初步检查。当尝试发布表单数据时调用此函数,如下所示:

<form id="form1" runat="server" onsubmit="return xssCheckValidates();">

该功能非常简单,可以改进,但它正在发挥作用。

请注意,这样做的目的不是为了保护系统免受黑客攻击,而是为了保护用户免受不良体验。在服务器上完成的请求验证仍然打开,这是系统保护的(一部分)(在它能够做到的范围内)。

我在这里说“部分”的原因是因为我听说内置的请求验证可能不够,所以可能需要其他补充手段来提供全面保护。但是,我在这里介绍的JavaScript函数与保护系统有什么都没有关系。它是只有旨在确保用户不会有糟糕的体验。

你可以在这里试试:

    function xssCheckValidates() {var valid = true;var inp = document.querySelectorAll("input:not(:disabled):not([readonly]):not([type=hidden])" +",textarea:not(:disabled):not([readonly])");for (var i = 0; i < inp.length; i++) {if (!inp[i].readOnly) {if (inp[i].value.indexOf('<') > -1) {valid = false;break;}if (inp[i].value.indexOf('&#') > -1) {valid = false;break;}}}if (valid) {return true;} else {alert('In one or more of the text fields, you have typed\r\nthe character "<" or the character sequence "&#".\r\n\r\nThis is unfortunately not allowed since\r\nit can be used in hacking attempts.\r\n\r\nPlease edit the field and try again.');return false;}}
<form onsubmit="return xssCheckValidates();" >Try to type < or &# <br/><input type="text" /><br/><textarea></textarea><input type="submit" value="Send" /></form>

我知道这个问题是关于表单发布的,但我想为在其他情况下收到此错误的人添加一些细节。它也可能发生在用于实现Web服务的处理程序上。

假设您的Web客户端使用ajax发送POST或PUT请求,并将json或xml文本或原始数据(文件内容)发送到您的Web服务。因为您的Web服务不需要从Content-Type标头中获取任何信息,所以您的JavaScript代码没有将此标头设置为您的ajax请求。但是,如果您没有在POST/PUT ajax请求上设置此标头,Safari可能会添加此标头:“Content-Type:Application/x-www-form-urlencoded”。我在iPhoneSafari6上观察到,但其他Safari版本/OS或Chrome可能会做同样的事情。所以当接收到此Content-Type标头的某些部分时。NET Framework假设请求主体数据结构对应于html表单发布,而它不对应,并引发HttpRequest estValidationException异常。要做的第一件事显然是始终将Content-Type标头设置为POST/PUT ajax请求上的表单MIME类型之外的任何类型,即使它对您的Web服务毫无用处。

我还发现了这个细节:
在这些情况下,当您的代码尝试访问HttpRequest. Params集合时,HttpRequest estValidationException异常会上升。但令人惊讶的是,当它访问HttpRequest. ServerVariables集合时,此异常不会上升。这表明,虽然这两个集合似乎几乎相同,但一个通过安全检查访问请求数据,另一个没有。

对于那些不使用模型绑定、从Request. Form中提取每个参数、确定输入文本不会造成伤害的人来说,还有另一种方法。不是一个很好的解决方案,但它会完成工作。

从客户端,将其编码为uri然后发送。
例如:

encodeURIComponent($("#MsgBody").val());

从服务器端,接受它并将其解码为uri。
例如:

string temp = !string.IsNullOrEmpty(HttpContext.Current.Request.Form["MsgBody"]) ?System.Web.HttpUtility.UrlDecode(HttpContext.Current.Request.Form["MsgBody"]) :null;

string temp = !string.IsNullOrEmpty(HttpContext.Current.Request.Form["MsgBody"]) ?System.Uri.UnescapeDataString(HttpContext.Current.Request.Form["MsgBody"]) :null;

请查看UrlDecodeUnescapeDataString之间的差异

在我的例子中,使用asp: Textbox控件(Asp.net4.5),而不是设置validateRequest="false"的所有页面我用

<asp:TextBox runat="server" ID="mainTextBox"ValidateRequestMode="Disabled"></asp:TextBox>

在导致异常的文本框上。

如何在ASP.NET4.6.2中修复AjaxExtControlls的此问题:

我们在使用AjaxExtControlls富文本编辑器时也遇到了同样的问题。此问题是在从. NET 2.0升级到. NET 4.5之后立即出现的。我查看了所有SOF答案,但找不到不损害. NET 4.5提供的安全性的解决方案。

修复1(不推荐,因为它会降低应用程序安全性):我在更改此属性后进行了测试requestValidationMode = "2.0,它起作用了,但我担心安全功能。所以这是修复就像降低整个应用程序的安全性。

修复2(推荐):由于此问题仅在AjaxExtControl中发生,因此我终于能够使用以下简单代码解决此问题:

editorID.value = editorID.value.replace(/>/g, "&gt;");editorID.value = editorID.value.replace(/</g, "&lt;");

此代码在将请求发送到服务器之前在客户端(javascript)执行。请注意,editorID不是我们在html/aspx页面上的ID,而是AjaxExtControl内部使用的富文本编辑器的ID。

我有一个Web窗体应用程序,它有一个输入框注释字段的问题,用户有时会粘贴电子邮件文本,电子邮件标题信息中的“<”和“>”字符会悄悄进入并抛出此异常。

我从另一个角度解决了这个问题……我已经在使用Ajax Control Toolkit,所以我能够使用FilteredTextBox扩展器来防止这两个字符进入输入框。然后,用户复制粘贴文本将得到他们期望的结果,减去这些字符。

<asp:TextBox ID="CommentsTextBox" runat="server" TextMode="MultiLine"></asp:TextBox><ajaxToolkit:FilteredTextBoxExtender ID="ftbe" runat="server" TargetControlID="CommentsTextBox" filterMode="InvalidChars" InvalidChars="<>" />

没有一个答案对我有用。然后我发现,如果我删除以下代码,我可以让它工作:

//Register action filter via Autofac rather than GlobalFilters to allow dependency injectionbuilder.RegisterFilterProvider();builder.RegisterType<OfflineActionFilter>().AsActionFilterFor<Controller>().InstancePerLifetimeScope();

我只能得出结论,Autofac的注册过滤器提供程序中的某些内容破坏或覆盖了validateRequest属性

即使将<httpRuntime requestValidationMode="2.0">添加到web.config我仍然在使用WIF进行身份验证的应用程序中不断收到错误。
对我来说解决的是在<system.web>元素中添加<sessionState mode="InProc" cookieless="UseUri"/>