浏览器跨域及CSRF

作者: 木秋 时间: 2017-08-11 点击量: 199


一、浏览器同源策略。

1、 什么是浏览器跨域。

  JavaScript出于安全方面的考虑,不允许跨域调用其他页面的对象,即同源政策。

2、 什么是同源策略?

1995年,同源政策由 Netscape 公司引入浏览器。最初,它的含义是指,A网页设置的 Cookie,B网页不能打开,除非这两个网页"同源"。所谓"同源"指的是"三个相同"。

(1)协议相同

(2)域名相同

(3)端口相同

 

3、 同源政策的目的

同源策略的目的是为了保证用户信息的安全。防止恶意的网站盗取数据。

设想这样一个情景:A网站是一家银行,用户登录以后,又去浏览其他的网站B,如果网站B可以读取A网站的Cookie,那么B网站就可以使用用户的Cookie向A网站发起请求(包含表单内容的请求)。因为浏览器同时还规定,提交表单不受同源策略的限制(B网站的表单数据可以直接提交给A网站)。

4、 非同源的网站有哪些限制?

  (1)Cookie、LocalStorage和IndexDB无法获取。

  (2)DOM无法获得。

  (3)AJAX请求不能发送。

 

二、CSRF

1、CSRF是什么?

CSRF(Cross-site request forgery),中文名称:跨站请求伪造,也被称为:one click attack/session riding,缩写为:CSRF/XSRF。

 

 

2、CSRF的原理

blob.png

(图片源于互联网)

 

3、攻击例子。

 

(1)、银行网站A,它以GET请求来完成银行转账的操作,如:http://www. muqiu.com/zhuanzhang.php?toBankId=22&money=100

危险网站B,它里面有一段HTML的代码如下:

<img src=http://www.muqiu.com/Transfer.php?toBankId=11&money=1000>


首先,你登录了银行网站A,然后访问危险网站B。B中的<img>以GET的方式请求第三方资源(这里的第三方就是指银行网站了,原本这是一个合法的请求,但这里被不法分子利用了),所以你的浏览器会带上你的银行网站A的Cookie发出Get请求,去获取资源“http://www.mybank.com/Transfer.php?toBankId=11&money=1000”,结果银行网站服务器收到请求后,认为这是一个更新资源操作(转账操作),所以就立刻进行转账操作。(GET请求不应该用来更新资源!!!!!)

 

(2)银行网站A的WEB表单如下

<form action="Transfer.php" method="POST">
    <p>ToBankId: <input type="text" name="toBankId" /></p>
    <p>Money: <input type="text" name="money" /></p>
    <p><input type="submit" value="Transfer" /></p>
  </form>

后台处理页面Transfer.php如下:

 <?php
    session_start();
    if (isset($_REQUEST['toBankId'] && isset($_REQUEST['money']))
    {
        buy_stocks($_REQUEST['toBankId'], $_REQUEST['money']);
    }
  ?>

危险网站B,包含以下这句HTML代码:

 <img src=http://www.mybank.com/Transfer.php?toBankId=11&money=1000>

 

银行后台使用了$_REQUEST去获取请求的数据,而$_REQUEST既可以获取GET请求的数据,也可以获取POST请求的数据,这就造成了在后台处理程序无法区分这到底是GET请求的数据还是POST请求的数据。所以还是会被攻击。

 

(3)如果上面的后端改用$_POST,只获取POST请求的数据,后台处理页面Transfer.php代码如下:

  <?php

    session_start();

    if (isset($_POST['toBankId'] && isset($_POST['money']))

    {

        buy_stocks($_POST['toBankId'], $_POST['money']);

    }

  ?>


  此时危险网站B与时俱进,它改了一下代码:

<html>

  <head>

    <script type="text/javascript">

      function steal()

      {

               iframe = document.frames["steal"];

               iframe.document.Submit("transfer");

      }

    </script>

  </head>

 

  <body onload="steal()">

    <iframe name="steal" display="none">

      <form method="POST" name="transfer" action="http://www.myBank.com/Transfer.php">

        <input type="hidden" name="toBankId" value="11">

        <input type="hidden" name="money" value="1000">

      </form>

    </iframe>

  </body>

</html>

如果用户仍是继续上面的操作,很不幸,仍然会遭受攻击,因为这里危险网站B暗地里发送了POST请求到银行!


其实可以看出,CSRF攻击是源于WEB的隐式身份验证机制!WEB的身份验证机制虽然可以保证一个请求是来自于某个用户的浏览器,但却无法保证该请求是用户批准发送的!

 

4、CSRF的防御

 

  1.服务端进行CSRF防御

 

  服务端的CSRF方式方法很多样,但总的思想都是一致的,就是在客户端页面增加伪随机数。

  (1).Cookie Hashing(所有表单都包含同一个伪随机值): 

  这可能是最简单的解决方案了,因为攻击者不能获得第三方的Cookie(理论上),所以表单中的数据也就构造失败了:>

  <?php

    //构造加密的Cookie信息

    $value = “DefenseSCRF”;

    setcookie(”cookie”, $value, time()+3600);

  ?>

  在表单里增加Hash值,以认证这确实是用户发送的请求。


  <?php

    $hash = md5($_COOKIE['cookie']);

  ?>

  <form method=”POST” action=”transfer.php”>

    <input type=”text” name=”toBankId”>

    <input type=”text” name=”money”>

    <input type=”hidden” name=”hash” value=”<?=$hash;?>”>

    <input type=”submit” name=”submit” value=”Submit”>

  </form>

  然后在服务器端进行Hash值验证

      <?php

        if(isset($_POST['check'])) {

             $hash = md5($_COOKIE['cookie']);

             if($_POST['check'] == $hash) {

                  doJob();

             } else {

        //...

             }

        } else {

      //...

        }

      ?>

  (2).验证码

  这个方案的思路是:每次的用户提交都需要用户在表单中填写一个图片上的随机字符串,这个方案可以完全解决CSRF。