ASP.NET MVC 防止CSRF攻击
简介
MVC中的Html.AntiForgeryToken()是用来防止跨站请求伪造(CSRF:Cross-site request forgery)攻击的一个措施,它跟XSS(XSS又叫CSS:Cross-Site-Script),攻击不同,XSS一般是利用站内信任的用户在网站内插入恶意的脚本代码进行攻击,而CSRF则是伪造成受信任用户对网站进行攻击。
CSRF可以攻击者盗用了你的身份,以你的名义发送恶意请求。CSRF能够做的事情包括:以你名义发送邮件,发消息,盗取你的账号,甚至于购买商品,虚拟货币转账......造成的问题包括:个人隐私泄露以及财产安全。
实例
我们新建一个简单的网站发布公告界面
@{ Layout = null; } <!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width" /> <title>Index</title> </head> <body> @using (Html.BeginForm("Notice", "Home", FormMethod.Post)) { @:网站公告:<input type="text" name="Notice" id="Notice" /> <input type="submit" value="Submit" /> } </body> </html>
提交后
此时提供给了跨站攻击的漏洞,CSRF一般依赖几个条件
(1)攻击者知道该目标站点。
(2)攻击者的目标站点具有持久化授权cookie或者受害者具有当前会话cookie
(3)目标站点没有对用户在网站行为的第二授权。
比如我们现在知道发布新闻的地址:http://localhost:56874/Home/Notice
比如我们新建一个页面
@{ Layout = null; } <!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width" /> <title>Index</title> </head> <body> <form action="http://localhost:56874/Home/Notice" method="post"> 网站公告:<input type="text" name="Notice" id="Notice" /> <input type="submit" value="Submit" /> </form> </body> </html>
发起攻击
这样在网站的公告就被篡改了。作为安全性考虑,这种情况肯定不会让它发生的。
如何防止
ASP.NET MVC中通过在页面上使用 Html.AntiForgeryToken()配合在对应的Action上增加[ValidateAntiForgeryToken]特性来防止跨站攻击。
修改上面提交代码
@using (Html.BeginForm("Notice", "Home", FormMethod.Post)) { @Html.AntiForgeryToken(); @:网站公告:<input type="text" name="Notice" id="Notice" /> <input type="submit" value="Submit" /> }
[HttpPost] [ValidateAntiForgeryToken] public ActionResult Notice(string Notice) { ViewBag.Notice = Notice; return View(); }
再次运行网站,界面没什么变化当我们查看源代码的时候发现多了一个东西
<input name="__RequestVerificationToken" type="hidden" value="oo1kDYx6CUL3YSyZHokvWgPzOcZhZID_75tiqYBgNMBBjQNo4FgmWpO5dRsVlvqIVgZH34FvTArCFbWKuDkCbwl5UFOAxzxmaTwuQ9iBBHY1" />
现在当我们再次篡改数据的时候

我们看一下Html.AntiForgeryToken()会为当前请求,生成一个名为__RequestVerificationToken的cookie,还有一个名为__RequestVerificationToken的隐藏域。


为了验证一个来自form post请求,还需要在目标action上增加[ValidateAntiForgeryToken]特性,它是一个验证过滤器,它主要检查
(1)请求的是否包含一个约定的AntiForgery名的cookie
(2)请求是否有一个Request.Form["约定的AntiForgery名"],约定的AntiForgery名的cookie和Request.Form值是否匹配
Ajax如何CSRF攻击
在Asp.net Mvc里加入防伪标记很简单在表单中加入Html.AntiForgeryToken()即可。
Html.AntiForgeryToken()会生成一对加密的字符串,分别存放在Cookies 和 input 中。
我们在ajax post中也带上AntiForgeryToken
<head>
    <meta name="viewport" content="width=device-width" />
    <title>Index</title>
    <script src="~/Script/jquery-1.10.2.min.js"></script>
</head>
<body>
    <form>
        网站公告:<input type="text" name="Notice" id="Notice" />
        <input type="button" value="提交" id="btn" />
    </form>
</body>
</html>
<script>
    $(function () {
        $("#btn").click(function () {
            var token = $('@Html.AntiForgeryToken()').val();
            var headers = {};
            headers["__RequestVerificationToken"] = token;
            $.ajax({
                type: 'POST',
                url: '/Home/Notice',
                cache: false,
                headers: headers,
                data: { Notice: $("#Notice").val()},
                success: function (data) {
                    alert(data)
                },
                error: function () {
                    alert("Error")
                }
            });
        })
    })
</script>自定义ValidateAntiForgeryToken
public class MyValidateAntiForgeryToken: AuthorizeAttribute { public override void OnAuthorization(AuthorizationContext filterContext) { var request = filterContext.HttpContext.Request; if (request.HttpMethod== WebRequestMethods.Http.Post) { if (request.IsAjaxRequest()) { var antiForgeryCookie = request.Cookies[AntiForgeryConfig.CookieName]; var cookiValue = antiForgeryCookie != null ? antiForgeryCookie.Value : null; var s = request.Headers["__RequestVerificationToken"]; AntiForgery.Validate(cookiValue, request.Headers["__RequestVerificationToken"]); } else { new ValidateAntiForgeryTokenAttribute() .OnAuthorization(filterContext); } } } }
修改HomeController Notice方法
[HttpPost] // [ValidateAntiForgeryToken] [MyValidateAntiForgeryToken] public ActionResult Notice(string Notice) { ViewBag.Notice = Notice; return Json(new { message = Notice }); }




                
            
        
浙公网安备 33010602011771号