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

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

捕获异常并显示

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

我觉得不够专业。

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

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

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


当前回答

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

其他回答

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

ASP.NET MVC–pages validateRequest=false不起作用?为什么ValidateInput(False)不工作?ASP.NET MVC RC1,VALIDATEINPUT,一个潜在的危险请求和陷阱

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

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

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

另一种解决方案是:

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

您可以在自定义模型活页夹中自动对字段进行HTML编码。我的解决方案有些不同,我将错误放在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);
        }
    }

在应用程序启动中:

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,不如看看Microsoft ACE团队提供的更新、更完整的反XSS库。