MVC中的Html.AntiForgeryToken()是用来防止跨站请求伪造(CSRF:Cross-site request forgery)攻击的一个措施,它跟XSS(XSS又叫CSS:Cross-Site-Script),攻击不一样,XSS通常是利用站内信任的用户在网站内插入恶意的脚本代码进行攻击,而CSRF则是伪形成受信任用户对网站进行攻击。html
举个简单例子,譬如整个系统的公告在网站首页显示,而这个公告是从后台提交的,我用最简单的写法:cookie
网站后台(Home/Index页面)设置首页公告内容,提交到HomeController的Text Action框架
HomeController的Text Actionpost
填写完公告,提交,显示网站
此时提供给了跨站攻击的漏洞,CSRF通常依赖几个条件spa
(1)攻击者了解受害者所在的站点3d
(2)攻击者的目标站点具备持久化受权cookie或者受害者具备当前会话cookiecode
(3)目标站点没有对用户在网站行为的第二受权orm
具体参见http://baike.baidu.com/view/1609487.htmxml
现假设我知道我要攻击的网站的地址,譬如是http://localhost:6060/Home/Text,且也知足2,3的状况。
因而我新建一个AntiForgeryText.html文件,内容以下:
在这个html中加了一个隐藏的字段,Name和Id和网站要接收的参数名同样。
我点击了“黑掉这个网站”,呈现以下
这个就是利用了漏洞把首页的公告给改了,这就是一个简单的跨站攻击的例子。
MVC中经过在页面上使用 Html.AntiForgeryToken()配合在对应的Action上增长[ValidateAntiForgeryToken]特性来防止跨站攻击。
把上面的代码改为
对应的Action
这样子我在AntiForgeryText.html中点"黑掉这个网站",就会出现
这样就防止了跨站攻击。
页面上的Html.AntiForgeryToken()会给访问者一个默认名为__RequestVerificationToken的cookie
为了验证一个来自form post,还须要在目标action上增长[ValidateAntiForgeryToken]特性,它是一个验证过滤器,
它主要检查
(1)请求的是否包含一个约定的AntiForgery名的cookie
(2)请求是否有一个Request.Form["约定的AntiForgery名"],约定的AntiForgery名的cookie和Request.Form值是否匹配
其中主要涉及到System.Web.WebPages.dll中的静态类AntiForgery
Html.AntiForgeryToken()调用了AntiForgery静态类的GetHtml方法,它产生一个随机值而后分别存储到客户端cookie和页面的hidden field中,
(1)Request.Cookies[antiForgeryTokenName](默认也是Request.Cookies["__RequestVerificationToken"])
(2)页面上的hiddenfield
其中cookie的key的名字和页面hidden field的名字是同样的,默认都是"__RequestVerificationToken",若是有提供ApplicationPath的话,那就是由"__RequestVerificationToken"和通过处理后的ApplicationPath组成。
Controller端则经过在Action上增长[ValidateAntiForgeryToken]特性来验证,
ValidateAntiForgeryTokenAttribute继承了FilterAttribute和IAuthorizationFilter,经过传递匿名委托方法,
委托调用AntiForgery类的Validate方法来实现验证。
Validate方法中主要验证Request.Cookies[antiForgeryTokenName]和<input name=antiForgeryTokenName ...>两个的值是否相同,
若是页面没有<input name=antiForgeryTokenName ...>,或者两个值不相等,就会抛出异常。
使用该方法的缺点是:
1. 这种方法是依赖于 cookie的,若是客户端禁止了 cookie ,那么这种防范就会失效。
2. 该方法是对 post请求有效,对 Get 请求无效
3. 对于 AJAX请求,MVC 框架不会自动传递 cookie和隐藏域。须要本身实现传输和读取。