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

我不想因为有人在文本框中输入了字符而引发异常或使整个web应用程序崩溃,但我正在寻找一种优雅的方式来处理这一问题。

捕获异常并显示

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

我觉得不够专业。

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

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

有没有办法让我从处理者那里做到这一点?


当前回答

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

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

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

我已经用它验证了正则表达式。我制作了自己的ValidationAttribute,以查看正则表达式是否有效。由于正则表达式可以包含类似于脚本的内容,我应用了上面的代码-正则表达式仍然在检查是否有效,但不检查是否包含脚本或HTML。

其他回答

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

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

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

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

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

然而,HyperLink、Literal和Label的.Text属性不会对内容进行HTML编码,因此包装Server.HtmlEncode();如果要防止<script>window.location=“http://www.google.com“;</script>被输出到页面并随后执行。

做一点实验,看看哪些被编码,哪些没有编码。

最后但同样重要的是,请注意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; }
}

案例提交值:&#39;

标签1.文本值:&#39;

TextBox2.文本值:&amp#39;

案例提交值:<script>alert('attack!')</脚本>

标签1.文本值:<script>alert('attack!')</脚本>

TextBox2.文本值:&lt;脚本&gt;警报(&#39;攻击!&#39;)&lt/脚本&gt;

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

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

与其使用Server.HtmlEncode,不如看看Microsoft ACE团队提供的更新、更完整的反XSS库。

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

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

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