1.XSRF:跨站请求伪造
XSRF即在访问B站点的时候,执行了A站点的功能。
比如:
A站点登录后,可以修改用户的邮箱(接口:/Email/Modify?email=123),修改邮箱时只验证用户有没有登录,而且登录信息是保存在cookie中。
用户登录A站点后,又打开一个窗口访问B站点,如果这时B站点内嵌入了一条链接http://www.A.com/Email/Modify?email=123,当用户点击这条链接时会直接修改A站点的用户邮箱。
2.ASP.NET 防XSRF攻击
ASP.NET提供了AntiForgery类防止XSRF攻击。 AntiForgery的使用如下:
在ASP.NET页面中添加如下代码
@Html.AntiForgeryToken()
在Controller的Action上添加属性ValidateAntiForgeryToken
[ValidateAntiForgeryToken]
public ActionResult IndexPost()
{
return View("~/Views/Home/Index.cshtml");
}
这样IndexPost就能防止XSRF攻击。
3.AntiForgery防XSRF攻击原理
在执行@Html.AntiForgeryToken()语句时,会在cookie中写入一个经过加密后的数据,并在页面中添加一个隐藏域一并写入加密后的数据(默认名称为__RequestVerificationToken)。当执行IndexPost(前面示例)方法前,会判断cookie中的数据与隐藏域的数据是否相等。相等则验证通过。否则会抛出异常。(Post请求会自动把隐藏域传递到后台,如果是Get请求,就需要手动把隐藏域的值传递到后台)。
待加密的数据是一个AntiForgeryToken对象。系统进行验证时,会先把加密的数据还原成AntiForgeryToken对象,对象有一个SecurityToken属性(用于填充随机序列),系统主要判断该字段的值是否相等。
同一个会话期间,SecurityToken数据相同,所以即使开多个tab访问相同页面,数据验证也会通过。
同一个会话期间cookie中的加密数据不会改变,因为访问页面时,cookie会传到后台,后台判断cookie中有加密数据,就不会重新生成cookie数据。但隐藏域的值每次都不同,因为每访问一次页面,都会重新加密一次,虽然AntiForgeryToken对象的值相同,但通过MachineKey的Protect加密后,每次加密的值都会不同。
AntiForgery使用MachineKey进行加密,所以如果系统使用负载均衡,就需要配置MachineKey,否则不同服务器的MachineKey不同,导致无法解密。
4.源码解析
1)在执行@Html.AntiForgeryToken()语句时,会调用GetHtml方法。GetHtml方法中会调用GetFormInputElement方法,该方法会在cookie中写入加密后的数据,并返回Html标签代码。该标签代码会写入到页面中。
public static HtmlString GetHtml()
{
if (HttpContext.Current == null)
{
throw new ArgumentException(WebPageResources.HttpContextUnavailable);
}
TagBuilder retVal = _worker.GetFormInputElement(new HttpContextWrapper(HttpContext.Current));
return retVal.ToHtmlString(TagRenderMode.SelfClosing);
}
2)在GetFormInputElement方法中,首先通过GetCookieTokenNoThrow方法获取Cookie中AntiForgeryToken对象(第一访问页面该对象为空)。再通过Get