Web开发中不可避免的要防止XSS,防止XSS当然要进行Encode(这里是广义,表示Encode和过滤掉特殊标签,下面不再解释),分为输出和输入。各有用处,比如,您提交保存并显示一块内容,那么多数情况下,您需要对输出进行Encode;对于搜索功能,您需要对查询条件进行(输入)Encode,例如:当在查询参数里面输入<scrpit>之类的东西时候您可能需要去掉它,得到所谓安全的参数,也就是查询id=111和查询id=111><script>出来的结果是一样的。我今天暂时尝试了对输入进行Encode。
MVC里面有一个机制非常有用,您可以利用它完成很多事情---ModelBinder。一个场景如下:注册账户(为了简单,仅仅有用户名和密码两个字段)。
public class User
{
public string UserName { get; set; }
public string PassWord { get; set; }
}
我们需要对post到action里面的内容进行Encode。利用ModerBinder,我们可以绑定参数值,当然我们重写一个ModerBinder,就可以进行Encode了。
public class ForbiddenXSSModelBinder : IModelBinder
{
#region IModelBinder 成员
public object BindModel(ControllerContext controllerContext,
ModelBindingContext bindingContext)
{
var valueProviderResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
if (valueProviderResult == null)
return null;
return Encoder.HtmlEncode(valueProviderResult.AttemptedValue);
}
#endregion
}
这里忽略了异常处理,和一些入口检查。简单的代码,完成了功能。
很快问题出来了:
1、我们对所以的参数都进行Encode,这是不对的。因为有些我们是不需要过滤(有些是不能,比如PassWord字段),比如创建时间字段
2、对所有字段进行Encode无疑是浪费性能的事情
那么,我们能不能根据定制进行Encode呢?我想到了Attribute,思路如下:
1、我们对User类需要Encode的属性进行标识
2、在ModerBinder的时候对类型的属性进行判断,进行确定是否要Encode
思路有了,代码实现很简单。先定义一个Attribute:
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
public class AllowEncodeAttribute : Attribute
{
/// <summary>
/// 判断是否需要Encode
/// </summary>
public bool AllowEncode { get; set; }
public AllowEncodeAttribute(bool allow)
{
AllowEncode = allow;
}
}
将User类更改:
[AllowEncode(true)]
public string UserName { get; set; }
在ModerBinder中这样操作:
public override object BindModel(ControllerContext controllerContext,
ModelBindingContext bindingContext)
{
DealInputValue(controllerContext.HttpContext.Request.QueryString);
DealInputValue(controllerContext.HttpContext.Request.Form);
var valueProviderResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
if (valueProviderResult == null)
return null;
Type type = bindingContext.ModelMetadata.ContainerType;
var propertyInfo = type.GetProperty(bindingContext.ModelName);
var attribute = Attribute.GetCustomAttribute(propertyInfo,
typeof(AllowEncodeAttribute)) as AllowEncodeAttribute;
if (attribute != null && attribute.AllowEncode == true)
{
return Encoder.HtmlEncode(valueProviderResult.AttemptedValue);
}
return valueProviderResult.AttemptedValue;
}
至此,尝试便结束了,初步达到了要求。
依然有一些问题存在:
1、对于参数并没有经过ModerBinder的我们怎么办?需要一个一个的Encode吗?
2、对于输出需要进行Encode的我们要如何?用HtmlHelper的Encode方法操作吗?
这是我下面要进行尝试的东西。