zoukankan      html  css  js  c++  java
  • CSRF防御之ASP.NET MVC

    MVC中的Html.AntiForgeryToken()是用来防止跨站请求伪造(CSRF:Cross-site request forgery)攻击的一个措施。

    举个简单例子,譬如整个系统的公告在网站首页显示,而这个公告是从后台提交的,我用最简单的写法:

    网站后台(Home/Index页面)设置首页公告内容,提交到HomeController的Text Action

    @using (Html.BeginForm("Text","Home",FormMethod.Post))
    {
        @:网站公告:<input type="text" name="Notice" id="Notice" />
        <input type="submit" value="Submit" />
    }

    HomeController的Text Action

     [HttpPost]
     public ActionResult Text()
     {
         ViewBag.Notice = Request.Form["Notice"].ToString();
         return View();
     }

    填写完公告,提交,显示

    此时提供给了跨站攻击的漏洞,CSRF一般依赖几个条件

    (1)攻击者了解受害者所在的站点

    (2)攻击者的目标站点具有持久化授权cookie或者受害者具有当前会话cookie

     

    (3)目标站点没有对用户在网站行为的第二授权此时

    具体参见http://baike.baidu.com/view/1609487.htm

    现假设我知道我要攻击的网站的地址,譬如是http://localhost:6060/Home/Text,且也满足2,3的情况。

    于是我新建一个AntiForgeryText.html文件,内容如下:

    复制代码
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml" >
    <head>
        <title></title>
    </head>
    <body>
        <form name="badform" method="post" action="http://localhost:6060/Home/Text">
            <input type="hidden" name="Notice" id="Notice" value="你的网站被我黑了。。" />
            <input type="submit" value="黑掉这个网站" />
        </form>
    </body>
    </html>
    复制代码

    在这个html中加了一个隐藏的字段,Name和Id和网站要接收的参数名一样。

    我点击了“黑掉这个网站”,呈现如下

     

    这个就是利用了漏洞把首页的公告给改了,这就是一个简单的跨站攻击的例子。

    MVC中通过在页面上使用 Html.AntiForgeryToken()配合在对应的Action上增加[ValidateAntiForgeryToken]特性来防止跨站攻击。

    把上面的代码改成

    @using (Html.BeginForm("Text","Home",FormMethod.Post))
    {
        @Html.AntiForgeryToken()
        @:网站公告:<input type="text" name="Notice" id="Notice" />
    <input type="submit" value="Submit" />
    }

    对应的Action

    复制代码
            [HttpPost]
            [ValidateAntiForgeryToken]
            public ActionResult Text()
            {
                ViewBag.Notice = Request.Form["Notice"].ToString();
                return View();
            }
    复制代码

    这样子我在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

    <input name="__RequestVerificationToken" type="hidden" value="9rUlMYvsH6eMcFN9tn/wRwAG07eROraVaeTn9hHMXKkMmDbR8jLw5DKdVnZBJ9siQHeGyl1w4rSB141LnxMp2ahV0qP1lElPeukqfcUFYoxrm/EfpSJjZavykmzn15VeGFMKkmgFj5a1UFhZFaW2aZgeN38x9lt0OFSoca7eMVU=" />

    其中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和隐藏域。需要自己实现传输和读取。

  • 相关阅读:
    解决:Could not resolve archetype org.apache.maven.archetypes
    Spring MVC配置MyBatis输出SQL
    Spring集成MyBatis 通用Mapper以及 pagehelper分页插件
    关于SpringMVC或Struts2接受参数接收不到的原因
    配置quartz启动时就执行一次
    ajaxFileUpload进行文件上传时,总是进入error
    spring mvc注入配置文件里的属性
    java中将一个文件夹下所有的文件压缩成一个文件
    flume failed to start agent because dependencies were not found in classpath
    ubuntu不能安装pip unable to install pip in unbuntu
  • 原文地址:https://www.cnblogs.com/wangchaozhi/p/5059798.html
Copyright © 2011-2022 走看看