关于asp.net:从客户端检测到一个潜在危险的Request.Form值

A potentially dangerous Request.Form value was detected from the client

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

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

捕获异常并显示

An error has occurred please go back and re-type your entire form again, but this time please do not use <

我觉得不够专业。

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

理想情况下:当出现包含HTML限制字符的回发时,表单集合中的该发布值将自动进行HTML编码。所以我的文本框的EDOCX1[3]属性将是EDOCX1[4]

有没有一种方法可以从一个处理程序做到这一点?


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

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

此外,"<本身并不危险。只有在特定的上下文中才是危险的:当编写尚未编码为HTML输出的字符串时(因为XSS)。

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

底线是:不能过滤危险字符的随机输入,因为在正确的情况下,任何字符都可能是危险的。您应该在某些特定的字符可能变得危险的时候进行编码,因为它们交叉进入一个不同的子语言,在那里它们有特殊的含义。将字符串写入HTML时,应使用server.html encode对HTML中具有特殊含义的字符进行编码。如果将字符串传递给动态SQL语句,则应编码不同的字符(或者更好的做法是,让框架使用准备好的语句或类似语句为您编码)。

当您确定在向HTML传递字符串的任何地方使用HTML编码时,然后在您的.aspx文件中的<%@ Page ... %>指令中设置validateRequest="false"

在.NET 4中,您可能需要再做一点。有时还需要添加Web.CONFIG(参考)的EDOCX1 6。


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

  • ASP.NET MVC–pages validateRequest=false不起作用?
  • 为什么validateInput(false)不起作用?
  • ASP.NET MVC RC1、validateInput、潜在的危险请求和陷阱

C样品:

1
2
3
4
5
[HttpPost, ValidateInput(false)]
public ActionResult Edit(FormCollection collection)
{
    // ...
}

Visual Basic示例:

1
2
3
4
<AcceptVerbs(HttpVerbs.Post), ValidateInput(False)> _
Function Edit(ByVal collection As FormCollection) As ActionResult
    ...
End Function


在ASP.NET MVC(从版本3开始)中,可以将AllowHtml属性添加到模型的属性中。

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

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


如果您在.NET 4.0上,请确保将此项添加到标记内的web.config文件中:

1
<httpRuntime requestValidationMode="2.0" />

在.NET 2.0中,请求验证仅适用于aspx请求。在.NET 4.0中,它被扩展为包含所有请求。在处理.aspx时,您可以通过指定以下内容恢复到仅执行XSS验证:

1
requestValidationMode="2.0"

您可以通过指定以下内容完全禁用请求验证:

1
validateRequest="false"


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

1
2
3
4
5
6
7
8
9
10
<configuration>
...
  <location path="MyFolder/.aspx">
    <system.web>
      <pages validateRequest="false" />
      <httpRuntime requestValidationMode="2.0" />
    </system.web>
  </location>
...
</configuration>

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

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


前面的答案很好,但是没有人说过如何排除一个字段被验证为HTML/javascript注入。我不知道以前的版本,但在MVC3测试版中,您可以这样做:

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

这仍然会验证除排除字段之外的所有字段。这样做的好处是,验证属性仍然验证字段,但您没有收到"潜在危险的请求。从客户端检测到表单值"异常。

我用它来验证正则表达式。我创建了自己的validationAttribute来查看正则表达式是否有效。因为正则表达式可以包含类似于脚本的内容,所以我应用了上面的代码——如果正则表达式有效与否,它仍然会被检查,但是如果它包含脚本或HTML,则不会被检查。


在ASP.NET MVC中,需要在web.config中设置requestvalidationmode="2.0"和validateRequest="false",并将validateInput属性应用于控制器操作:

1
2
3
4
5
6
7
<httpRuntime requestValidationMode="2.0"/>

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

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


您可以对文本框内容进行HTML编码,但遗憾的是,这并不能阻止异常的发生。根据我的经验,没有办法,你必须禁用页面验证。你这样做是在说:"我会小心的,我保证。"


对于MVC,通过添加

[ValidateInput(false)]

在控制器中的每个动作上方。


您可以在global.asax中捕获该错误。我仍然想验证,但显示适当的消息。在下面列出的博客上,有这样的示例。

1
2
3
4
5
6
7
8
9
10
11
12
    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控件将自动对输出进行HTML编码。例如,在文本框控件上设置.text属性将自动对其进行编码。具体地说就是把<转换成<>转换成>&转换成&。所以要小心这样做…

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

但是,hyperlink、literal和label的.text属性不会对事物进行HTML编码,因此如果要防止 window.location ="http://www.google.com"; 被输出到您的页面并随后执行,则必须将server.html encode()包装在这些属性上设置的任何内容周围。

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


这个问题的答案很简单:

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

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


在web.config文件的标记中,插入带有属性requestvalidationmode="2.0"的httpruntime元素。同时在pages元素中添加validateRequest="false"属性。

例子:

1
2
3
4
5
6
7
<configuration>
  <system.web>
   <httpRuntime requestValidationMode="2.0" />
  </system.web>
  <pages validateRequest="false">
  </pages>
</configuration>


如果不想禁用validateRequest,则需要实现一个javascript函数以避免出现异常。这不是最好的选择,但很有效。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
function AlphanumericValidation(evt)
{
    var charCode = (evt.charCode) ? evt.charCode : ((evt.keyCode) ? evt.keyCode :
        ((evt.which) ? evt.which : 0));

    // User type Enter key
    if (charCode == 13)
    {
        // Do something, set controls focus or do anything
        return false;
    }

    // User can not type non alphanumeric characters
    if ( (charCode <  48)                     ||
         (charCode > 122)                     ||
         ((charCode > 57) && (charCode < 65)) ||
         ((charCode > 90) && (charCode < 97))
       )
    {
        // Show a message or do something
        return false;
    }
}

然后在代码隐藏中的pageload事件中,用下一个代码将属性添加到控件中:

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


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

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

我不知道有没有什么不好的地方,但对我来说,这真是太好了。


另一个解决方案是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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 here
            if (requestValidationSource == RequestValidationSource.Form ||
                requestValidationSource == RequestValidationSource.QueryString)

                return true; // Suppress error message
        }
        return result;
    }
}


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

1
2
3
4
5
<configuration>
    <system.web>
        <pages validateRequest="false" />
    </system.web>
</configuration>

如果您使用的是框架4.5,那么web.config中的条目(requestvalidationmode="2.0")。

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

如果只需要一页,那么在您的ASPX文件中,您应该将第一行如下所示:

1
<%@ Page EnableEventValidation="false" %>

如果您已经有了<%@页面,那么只需添加其余的=>EnableEventValidation="false"%>

我建议不要这样做。


在ASP.NET中,您可以捕获异常并对其进行一些处理,例如显示友好消息或重定向到另一页…还有一种可能性,你可以自己处理验证…

显示友好消息:

1
2
3
4
5
6
7
8
9
10
11
12
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();
    }
}

我想你可以在一个模块中完成它,但是这会带来一些问题;如果你想把输入保存到数据库中呢?突然,因为您将编码数据保存到数据库中,所以最终信任来自它的输入,这可能是个坏主意。理想情况下,您将原始未编码数据存储在数据库中,并每次编码。

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

与使用server.htmlencode相比,您应该查看来自Microsoft ACE团队的更新、更完整的Anti-XSS库。


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

  • 将文本框设置为HTML元素(如文本区域),而不是ASP元素。
  • 添加隐藏字段。
  • 将以下javascript函数添加到头部。

    函数boo()。{targetText=document.getElementByID("hiddenfield1");sourceText=document.getElementByID("用户框");targetText.value=转义(sourceText.innerText);}

在文本区域中,包括调用boo()的onchange:

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

最后,在.NET中,使用

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

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

下面是一个示例i(mc9000)通过jquery提出并使用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$(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
    });


});

和标记:

1
<textarea id="txtHTML"></textarea>

这很管用。如果黑客试图通过绕过javascript来发帖,他们只会看到错误。您还可以将所有这些编码的数据保存在数据库中,然后(在服务器端)对其进行解压缩,并在显示到其他地方之前分析和检查攻击。


这里的其他解决方案也很不错,但是必须将[allowhtml]应用到每一个模型的属性上有点皇家的痛苦,特别是在一个相当大的站点上有超过100个模型的情况下。

如果像我一样,你想把这个(imho-pretty-pointless)功能关闭在站点范围内,你可以覆盖你的基础控制器中的execute()方法(如果你还没有一个基础控制器,我建议你做一个,它们对于应用公共功能非常有用)。

1
2
3
4
5
6
    protected override void Execute(RequestContext requestContext)
    {
        // Disable requestion validation (security) across the whole site
        ValidateRequest = false;
        base.Execute(requestContext);
    }

只需确保您是HTML编码从用户输入输出到视图的所有内容(无论如何,它是使用Razor的ASP.NET MVC 3中的默认行为,因此除非出于某种奇怪的原因,您使用的是html.raw(),否则不应需要此功能。


如果您确实需要诸如><等特殊字符,请禁用页面验证。然后确保在显示用户输入时,数据是HTML编码的。

页面验证存在安全漏洞,因此可以绕过它。同样,页面验证也不应该单独依赖。

参见:http://web.archive.org/web/20080913071637/http://www.procheckup.com:80/pdfs/bypassing-dot-net-validaterequest.pdf


原因

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

解决方案

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

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

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

1
<pages validateRequest ="false" />

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

1
<httpRuntime requestValidationMode ="2.0" />

就是这样。我希望这能帮助你解决上述问题。

引用者:ASP.NET错误:潜在危险的请求。从客户端检测到表单值


我也收到了这个错误。

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

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

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

而不是

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

这样做

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

江户十一〔二〕耍了这个花招。

我得到的角色名是html值roleName="Cadastro bás"。该值与HTML实体á一起被ASP.NET MVC阻止。现在我得到了应该的roleName参数值:roleName="Cadastro Básico"和asp.net mvc引擎不再阻塞请求。


您还可以使用javascript的转义(字符串)函数替换特殊字符。然后服务器端使用server.urldecode(string)将其切换回。

这样,您就不必关闭输入验证,而且对于其他程序员来说,字符串可能包含HTML内容将更加清楚。


我在每次回发之前都会使用javascript来检查您不想要的字符,例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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;
}

当然,我的页面主要是数据输入,很少有元素进行回发,但至少保留了它们的数据。


所有的建议对我都不起作用。无论如何,我不想关闭整个网站的这个功能,因为99%的时候我不希望我的用户在Web表单上放置HTML。我刚刚创建了自己的工作区方法,因为我是唯一使用这个特定应用程序的人。我将输入转换为后面代码中的HTML,并将其插入到我的数据库中。


您可以使用如下内容:

1
var nvc = Request.Unvalidated().Form;

后来,nvc["yourKey"]应该起作用了。


只要这些只是"<"和">"(而不是双引号本身)字符,并且您在上下文中使用它们,如,那么您是安全的(而对于您当然是易受攻击的)。这可能会简化您的情况,但对于更多的问题,请使用其他已发布的解决方案之一。


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


您可以在自定义模型活页夹中自动HTML编码字段。我的解决方案有些不同,我把错误放在ModelState中,并在字段附近显示错误消息。为了自动编码,很容易修改这个代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
 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);
        }
    }

在应用程序中启动:

1
ModelBinders.Binders.DefaultBinder = new AppModelBinder();

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
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;
        }
    }
}

错误控制器:

1
2
3
4
5
6
7
public class ErrorController : Controller
 {
   public ActionResult InvalidUrl()
   {
      return View();
   }
}


您应该使用server.htmlencode方法来保护站点不受危险输入的影响。

更多信息在这里


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

1
2
3
4
5
6
7
8
9
10
11
12
13
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);
    }
}

对于那些不使用模型绑定的人,他们正在从request.form中提取每个参数,他们确信输入文本不会造成任何伤害,还有另一种方法。不是一个很好的解决方案,但它可以完成这项工作。

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

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

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

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

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

请查看UrlDecodeUnescapeDataString之间的差异。


对于那些仍然停留在webforms上的人,我发现了以下解决方案,使您只能在一个字段上禁用验证!(我不想整个页面都禁用它。)

VB.NET:

1
2
3
4
5
6
Public Class UnvalidatedTextBox
    Inherits TextBox
    Protected Overrides Function LoadPostData(postDataKey As String, postCollection As NameValueCollection) As Boolean
        Return MyBase.LoadPostData(postDataKey, System.Web.HttpContext.Current.Request.Unvalidated.Form)
    End Function
End Class

C:

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

现在只需使用而不是,它应该允许所有字符(这对于密码字段是完美的!)


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

假设您的Web客户机使用Ajax发送POST或PUT请求,并向Web服务发送JSON或XML文本或原始数据(文件内容)。因为您的Web服务不需要从内容类型头中获取任何信息,所以您的javascript代码没有将此头设置为Ajax请求。但是,如果您没有在post/put-ajax请求上设置这个头,safari可能会添加这个头:"content-type:application/x-www-form-urlencoded"。我注意到在iPhone上的Safari 6上,但其他Safari版本/OS或Chrome也可以这样做。因此,在接收此内容类型头时,.NET框架的某些部分假定请求主体数据结构与HTML表单发布相对应,而不是,并引发httpRequestValidationException异常。首先要做的显然是,在post/put-ajax请求上,总是将content-type头设置为除表单mime类型之外的任何类型,即使它对您的Web服务没有用处。

我还发现了这个细节:在这些情况下,当代码尝试访问httpRequest.params集合时,httpRequestValidationException异常将上升。但令人惊讶的是,当访问httprequest.servervariables集合时,这个异常并没有增加。这表明,尽管这两个集合看起来几乎相同,但一个通过安全检查访问请求数据,另一个则不相同。


解决方案

我不想关闭后验证(validateRequest="false")。另一方面,应用程序崩溃是不可接受的,因为一个无辜的用户碰巧在或其他类型上发生了故障。

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

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

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

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

我之所以在这里说"是的一部分",是因为我听说内置请求验证可能不够,所以可能需要其他补充方法来进行完全保护。但是,我在这里介绍的javascript函数与保护系统无关。这只是为了确保用户不会有不好的体验。

你可以在这里试试:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
    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

the character"<" or the character sequence"&#".



This is unfortunately not allowed since

it can be used in hacking attempts.



Please edit the field and try again.');
        return false;
      }
    }
1
2
3
4
5
6
<form onsubmit="return xssCheckValidates();">
  Try to type < or &# <br/>
  <input type="text" /><br/>
  <textarea></textarea>
  <input type="submit" value="Send" />
</form>


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

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

最后,请注意ASP.NET数据绑定控件在数据绑定期间自动对值进行编码。这将更改包含在ItemTemplate中的所有ASP.NET控件(文本框、标签等)的默认行为。下面的示例演示(ValidateRequest设置为false):

阿斯克斯

1
2
3
4
5
6
7
8
9
10
11
<%@ Page Language="C#" ValidateRequest="false" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="WebApplication17._Default" %> <html> <body>
    <form runat="server">
       
            <ItemTemplate>
                </asp:TextBox>
               
               "></asp:Label>
               "></asp:TextBox>
            </ItemTemplate>
        </asp:FormView>
    </form>

代码落后

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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; }
}
  • 案件提交值:'
  • Label1.Text值:'

    TextBox2.Text值:&#39;

  • 案件提交值:alert('attack!');
  • Label1.Text值:alert('attack!');

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


    在我的例子中,使用asp:textbox控件(asp.net 4.5),而不是设置validateRequest="false"的所有页面。我用过

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

    在导致异常的文本框上。


    我看到有很多关于这个的文章……我没有看到提到这个。这是从.NET Framework 4.5开始提供的

    控件的validateRequestMode设置是一个很好的选项。这样,页面上的其他控件仍然受到保护。不需要更改web.config。

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


    使用Server.HtmlEncode("yourtext");


    尝试用

    Server.Encode

    Server.HtmlDecode
    while sending and receiving.