使用MVC Razor进行输入消毒 - 如何安全?

时间:2014-03-25 04:03:16

标签: asp.net-mvc-4 razor xss

如果我有一个带有文本字段的标准注册表单,并且我在其中键入脚本标记,MVC会发回一个错误,说明"从客户端检测到一个潜在危险的Request.Form值"。这只是一个调试错误吗?我的用户会在实际网站上看到这个吗?

是否有一种安全简便的方法可以默默地接受和编码/清理字段中的输入,这样MVC就不会产生可怕的错误,但输入是无害的?

显然我也想确保我的输出是编码的,但Razor在很大程度上会处理这个问题,并且我对@Html.Raw小心谨慎。我们也已经通过使用参数化查询来处理数据库输入,因此SQL注入不应该是一种威胁。

2 个答案:

答案 0 :(得分:5)

"从客户端检测到一个潜在危险的Request.Form值"异常不仅仅是一个调试错误,而且是一个将在部署服务器上传播的错误。因此,您的用户将在实时服务器上看到此错误(或您的自定义错误页面)。

要允许未经过清理的HTML成功绑定到您的模型,您可以执行以下任何操作:

  1. 使用[AllowHtml]属性
  2. 装饰您的SignUp模型属性
  3. 使用[ValidateInput( false )]属性
  4. 装饰您的SignUp控制器操作
  5. 如果您正在使用MVC v4.0,请在您的web.config中包含以下内容:

    <location path="Accounts/SignUp"> <system.web> <pages validateRequest="false" /> <httpRuntime requestValidationMode="2.0" /> </system.web> </location>

  6. 我再说一遍,以上所有内容都允许将未经过清理的HTML绑定到您的模型。这意味着没有&#34;从客户端检测到潜在危险的Request.Form值&#34;错误,但您的输入将不会被清理,并且仍然可能包含可能有害的标签。

    要允许将清理后的输入绑定到模型,您可以调整Customizing property binding through attributes中的PropertyBindAttribute实现,以允许您使用[AllowSanitizedHtml]属性修饰模型属性,您希望在该属性中允许该功能在清理后接受HTML输入。对于清理,您可以使用Microsoft.Security.Application.Encoder.Encode()帮助程序方法(NuGet程序包名称:&#39; AntiXSS&#39;)

    首先,提供用于自然绑定的基类的属性:

    [AttributeUsage( AttributeTargets.Property , AllowMultiple = false )]
    public abstract class AbstractPropertyBinderAttribute :
        Attribute
    {
    
        public abstract bool BindProperty(
            ControllerContext controllerContext ,
            ModelBindingContext bindingContext ,
            PropertyDescriptor propertyDescriptor
            );
    
    }
    

    然后,知道此属性的自定义模型绑定器,以便模型绑定可以处理属性属性绑定的特殊情况:

    public class CustomModelBinder : 
        DefaultModelBinder
    {
    
        protected override void BindProperty(
            ControllerContext controllerContext ,
            ModelBindingContext bindingContext , 
            PropertyDescriptor propertyDescriptor )
        {
            if( propertyDescriptor.Attributes.OfType<AbstractPropertyBinderAttribute>().Any() )
            {
                var modelBindAttr = propertyDescriptor.Attributes.OfType<AbstractPropertyBinderAttribute>().FirstOrDefault();
    
                if( modelBindAttr.BindProperty(
                        controllerContext ,
                        bindingContext ,
                        propertyDescriptor ) )
                {
                    return;
                }
            }
    
            base.BindProperty(
                controllerContext ,
                bindingContext ,
                propertyDescriptor
                );
        }
    }
    

    不要忘记将以下代码添加到Global.asax中,以允许将CustomModelBinder用作默认值:

    System.Web.Mvc.ModelBinders.Binders.DefaultBinder = new CustomModelBinder();
    

    最后,AllowSanitizedHtmlAttribute

    public class AllowSanitizedHtmlAttribute :
        AbstractPropertyBinderAttribute ,
        IMetadataAware
    {
    
        public override bool BindProperty(
            ControllerContext controllerContext ,
            ModelBindingContext bindingContext ,
            PropertyDescriptor propertyDescriptor )
        {
            if( propertyDescriptor.PropertyType == typeof( string ) )
            {
                var unvalidatedValueProvider = bindingContext.ValueProvider as IUnvalidatedValueProvider;
                var result = unvalidatedValueProvider.GetValue(
                    propertyDescriptor.Name ,
                    true 
                    );
    
                if( result != null )
                {
                    propertyDescriptor.SetValue(
                        bindingContext.Model ,
                        Encoder.HtmlEncode( result.AttemptedValue )
                        );
                    return true;
                }
            }
    
            return false;
        }
    
    
        #region IMetadataAware Members
    
        public void OnMetadataCreated( ModelMetadata metadata )
        {
            if( metadata == null )
                throw new ArgumentNullException( "metadata" );
    
            metadata.RequestValidationEnabled = false;
        }
    
        #endregion
    
    }
    

    现在,您可以使用[AllowSanitizedHtml]属性安全地装饰需要在SignUp表单中进行清理的模型属性。这将允许您的模型属性的输入在被清理后以静默方式绑定。

答案 1 :(得分:0)

您可以使用[ValidateInput(false)]属性修饰您的操作。这将导致对任何调用特定操作的请求绕过请求验证。

或者,您可以使用[AllowHtml]属性修饰模式中的特定属性。

如果您不这样做,并且您没有提供自定义错误页面,那么如果用户尝试将HTML标记作为请求的一部分传递,则会看到某种错误消息。这可以是发布值,查询字符串,URL甚至是cookie。

有关MSDN的更多信息,请访问:http://msdn.microsoft.com/en-us/library/hh882339(v=vs.110).aspx