提问



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


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


捕获异常并显示



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



对我来说似乎不够专业。


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


理想情况下:当发回包含HTML限制字符的回发时,Form集合中的已发布值将自动进行HTML编码。
所以我的文本框的.Text属性将是something & lt; html & gt;


有没有办法可以从处理程序中执行此操作?

最佳参考


我认为你是通过尝试编码所有发布的数据从错误的角度攻击它。


请注意,<也可能来自其他外部源,如数据库字段,配置,文件,订阅源等。


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


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


底线是:你不能过滤危险字符的随机输入,因为在适当的情况下任何字符都可能是危险的。你应该在某些特定字符可能变得危险的位置进行编码,因为它们会进入不同的子语言它们具有特殊意义。当你将字符串写入HTML时,你应该使用Server.HtmlEncode对HTML中具有特殊含义的字符进行编码。如果你将字符串传递给动态SQL语句,你应该编码不同的字符(或者更好,让框架通过使用预处理语句等为您完成。


当你确定在任何地方进行HTML编码时都会将字符串传递给HTML,然后在.aspx文件的<%@ Page ... %>指令中设置validateRequest="false"


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

其它参考1


如果你正在使用ASP.NET MVC,那么这个错误会有不同的解决方案:



  • ASP.NET MVC - pages validateRequest=false不起作用?

  • 为什么ValidateInput(False)不起作用?

  • ASP.NET MVC RC1,VALIDATEINPUT,潜在的危险请求和PITFALL



C#样本:[73] [75]


[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

其它参考2


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


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


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

其它参考3


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


<httpRuntime requestValidationMode="2.0" />





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


requestValidationMode="2.0"


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


validateRequest="false"

其它参考4


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


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


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


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

其它参考5


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


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


这仍然验证除被排除的字段之外的所有字段。关于这一点的好处是你的验证属性仍然验证字段,但你只是没有得到从客户端检测到一个潜在危险的Request.Form值异常。


我已经用它来验证正则表达式。我已经创建了自己的ValidationAttribute来查看正则表达式是否有效。由于正则表达式可以包含看起来像脚本的东西我应用了上面的代码 - 如果正则表达式有效或无效,它仍然被检查,但如果它包含脚本或HTML则不然。

其它参考6


在ASP.NET MVC中,您需要在web.config中设置requestValidationMode =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) {
    ...
}

其它参考7


你可以HTML编码文本框内容,但不幸的是,它不会阻止异常发生。根据我的经验,没有办法,你必须禁用页面验证。通过这样做,你说:我会成为小心,我保证。[77]

其它参考8


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



  [[ValidateInput(假)]]



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

其它参考9


您可以在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[78]

其它参考10


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


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


但是,HyperLink,Literal和Label的.Text属性不会对HTML进行编码,所以如果要阻止输出<script> window.location = "http://www.google.com"; </script>,必须在这些属性上设置包装Server.HtmlEncode();进入你的页面并随后执行。


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

其它参考11


这个问题的答案很简单:


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


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

其它参考12


在web.config文件中,在标记内插入带有属性requestValidationMode =2.0的httpRuntime元素。还要在pages元素中添加validateRequest =false属性。


例:


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

其它参考13


如果你不想禁用ValidateRequest,你需要实现一个JavaScript函数,以避免异常。它不是最好的选择,但它的工作原理。


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事件中,使用下一个代码将属性添加到控件:


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

其它参考14


似乎没有人提到下面的内容,但它解决了我的问题。在任何人说是的之前它是Visual Basic ...哎呀。


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


我不知道是否有任何缺点,但对我来说,这真的很棒。

其它参考15


另一种解决方案是


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;
    }
}

其它参考16


在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();
    }
}

其它参考17


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


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


您应该从Microsoft ACE团队那里查看更新,更完整的Anti-XSS库,而不是使用Server.HtmlEncode。[79]

其它参考18


如果您正在使用框架4.0,那么web.config中的条目(< pages validateRequest =false/>)


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


如果您正在使用框架4.5,那么web.config中的条目(requestValidationMode =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"%>


我建议不要这样做。

其它参考19


这里的其他解决方案都很不错,但是在后面必须将[[AllowHtml]]应用到每个Model属性上都有点痛苦,特别是如果你在一个体面的网站上有超过100个模型。


如果像我一样,你想在网站范围内转换这个(恕我直言,相当无意义)功能,你可以覆盖基本控制器中的Execute()方法(如果你还没有基本控制器,我建议你做一个,它们可以是对于应用常用功能非常有用)。


    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( )你不应该要求这个功能。

其它参考20


我也得到了这个错误。


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


我将角色名称传递给一个方法,以便向用户授予该角色,并且$.ajax帖子请求失败了......


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


代替


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


做这个


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


@Html.Raw成功了。


我将角色名称作为HTML值roleName="Cadastro b&#225;s"。 ASP.NET MVC阻止了HTML实体&#225;的这个值。现在我按照应该的方式得到roleName参数值:roleName="Cadastro Básico"并且ASP.NET MVC引擎不再阻止请求。

其它参考21


原因


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


解决方案


在许多情况下,您需要通过Rich TextBoxes或Rich Text Editors向页面提交HTML内容。在这种情况下,您可以通过将@Page指令中的ValidateRequest标记设置为false来避免此异常。


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


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


<pages validateRequest ="false" />


对于.NET 4.0或更高版本的框架,您还需要在< system.web>部分添加以下行以完成上述工作。


<httpRuntime requestValidationMode = "2.0" />


而已。我希望这可以帮助你摆脱上述问题。


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

其它参考22


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


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


请参阅:http://www.procheckup.com/PDFs/bypassing-dot-NET-ValidateRequest.pdf [83]

其它参考23


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


这样您就不必关闭输入验证,其他程序员可以更清楚地知道该字符串可能包含HTML内容。

其它参考24


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



  • 使文本框成为HTML元素(如textarea)而不是ASP文件。

  • 添加隐藏字段。

  • 将以下JavaScript函数添加到标题中。



        function boo(){
            targetText=document.getElementById(HiddenField1);
            sourceText=document.getElementById(userbox);
            targetText.value=escape(sourceText.innerText);
        }



在你的textarea中,包含一个调用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发布,他们只会看到错误。您也可以保存在数据库中编码的所有这些数据,然后将其转发(在服务器端),并解析和解析数据库。在其他地方显示之前检查攻击。

其它参考25


我在每次回发之前最终都使用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;
}


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

其它参考26


只要这些<和>(而不是双引号本身)字符,你在上下文中使用它们像< input value = this />,你是安全的(而对于< textarea> 这一个</textarea>当然你很容易受到伤害。这可能会简化您的情况,但对于任何更多地使用其他发布的解决方案。

其它参考27


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

其它参考28


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

其它参考29


您可以使用以下内容:


var nvc = Request.Unvalidated().Form;


后来,nvc["yourKey"]应该有效。