Ruby中有提供表单的令牌token,struts中也有提供token
今天为了增加表单提交的安全性,于是也想着在mvc里面模拟一个类似token的东西。
做法很简单,写两个filter就可以了,第一个用来产生token,并且将这个token存入Session或者Cookies中,这个filter在action产生前触发,于是生成的页面就可以在表单里面写一个hidden域来存放这个生成的token;另外还要再写一个filter来验证表单提交的时候hidden域中的token跟服务器端保存的token是否一致,这里可以在filter里面重写两个事件,一个在action触发之前判断,一个在action之后,让这个token失效或者重置。
自己实现后再翻查了一下资料,原来ASP.NET MVC从PV5开始就提供了类似这样的token:
先在提交页的表单中写
<%=Html.AntiForgeryToken() %>
这样就会在客户端页面上生成一个类似
Code
<input name="__MVC_AntiForgeryToken" type="hidden" value="FaSCzN4P+6Hg977mdOX4z9pCKOy4vlP6whi0RGD+2L9mbTNGGx4GmN36sE4klJZf" />
<input name="__MVC_AntiForgeryToken" type="hidden" value="FaSCzN4P+6Hg977mdOX4z9pCKOy4vlP6whi0RGD+2L9mbTNGGx4GmN36sE4klJZf" />
的隐藏域。然后只需要在action头部加上一个系统提供的过滤器,就可以达到目的了,如:
///
<summary>
/// /Home/Login 登陆
/// </summary>
[Microsoft.Web.Mvc.ValidateAntiForgeryToken]
public void Login()
/// /Home/Login 登陆
/// </summary>
[Microsoft.Web.Mvc.ValidateAntiForgeryToken]
public void Login()
其实这种令牌形式只是让安全性稍稍提高了一下,如果别人要外部提交表单,实际上这种方式照样可以被拦截下来。所有Request信息都是可以伪造的,所以最好的方法还是增加底层的安全性,如果用Linq to SQL生成实体的话,那么在model那里实际上就可以做过滤了,如:
partial
class
tips : ModelFilter
{
partial void OntitleChanged
{
_title = FilterContent(_title);
if (_title == string .Empty)
{
throw new Exception( " not null! " );
}
}
partial void OncontentChanged()
{
_content = FilterJS(_content);
if (_content == string .Empty)
{
throw new Exception( " not null! " );
}
}
}
{
partial void OntitleChanged
{
_title = FilterContent(_title);
if (_title == string .Empty)
{
throw new Exception( " not null! " );
}
}
partial void OncontentChanged()
{
_content = FilterJS(_content);
if (_content == string .Empty)
{
throw new Exception( " not null! " );
}
}
}
有一个tips的实体,只需要写一个过滤的基类,然后tips实体继承这个基类就可以了,上面只是简单的把title过滤掉HTML标签,把content过滤掉JS脚本,过滤一般是在Changed事件,如果放在changing事件中,赋值的时候又会把value重新赋给实体了。你也可以根据你的字段来做过滤,如写邮件格式或者电话号码格式的验证,这些格式验证的话就可以写在changing事件。前台验证并不能避免外部提交表单的问题,如果业务不过滤,实体不过滤,很容易就被别人攻击了。很多人主张写一个工具类在业务层那里过滤,需要过滤的地方就调用,使用什么方法都好,因人而异,我个人觉得把实体写完善了,才能减少工作量,因为说不准哪天你就忘记调用你的工具类去过滤了,回过头去找,很累。开blog第一篇,先写到这了。