迭戈

博客园 首页 新随笔 联系 管理

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了。

原始的ModelBinder
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:

AllowEncodeAttribute
[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中这样操作:

改进后的ModerlBinder
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方法操作吗?

这是我下面要进行尝试的东西。

posted on 2011-04-18 12:51  Will Meng  阅读(1757)  评论(6编辑  收藏  举报