澳门新浦京娱乐场网站-www.146.net-新浦京娱乐场官网
做最好的网站

CS福睿斯F攻击与堤防,跨站供给伪造

1、简介

  CSRF的全名为Cross-site request forgery,它的中文名为 跨站请求伪造(伪造跨站请求【这样读顺口一点】)

  CSRF是一种夹持用户在已经登陆的web应用程序上执行非本意的操作的攻击方式。相比于XSS,CSRF是利用了系统对页面浏览器的信任,XSS则利用了系统对用户的信任。

 

阅读目录

WEB安全中经常谈到的两个东西:XSS和CSRF。这两个概念在前端面试中也经常被问到,只要涉及到WEB安全的东西就必须提到他们哥俩,从我以往的面试经历中我多次死在这两个东西上,知道这两个东西但让我仔细描述下就瞎几把乱扯,结果可想而知。这几天也查阅了相关书籍,终于把这两个东西搞明白了,为此决定写篇文章来记录他们俩以备今后复习,这篇先介绍CSRF。

web安全中有很多种攻击手段,除了SQL注入外,比较常见的还有 XSS 和 CSRF等

2、CSRF攻击原理

下面为CSRF攻击原理图:

图片 1

由上图分析我们可以知道构成CSRF攻击是有条件的:

  1、客户端必须一个网站并生成cookie凭证存储在浏览器中

  2、该cookie没有清除,客户端又tab一个页面进行访问别的网站

 

  • 1、简介
  • 2、CSRF攻击原理
  • 3、CSRF例子与分析
  •   3.1、简单级别CSRF攻击
  •   3.2、中级别CSRF攻击
  •   3.3、高级别CSRF攻击
  • 4、CSRF防御方法
  • 5、参考文献

CSRF是什么鬼

CSRF(Cross Site Request Forgery) 跨站请求伪造。也被称为One Click Attack和Session Riding,通常缩写为CSRF或XSRF。如果从名字你还不不知道它表示什么,你可以这样理解:攻击者(黑客,钓鱼网站)盗用了你的身份,以你的名义发送恶意请求,这些请求包括发送邮件、发送消息、盗取账号、购买商品、银行转账,从而使你的个人隐私泄露和财产损失。

 

3、CSRF例子与分析

  我们就以游戏虚拟币转账为例子进行分析

回到顶部

CSRF漏洞现状

CSRF这种攻击方式在2000年已经被国外的安全人员提出,但在国内,直到2006年才开始被关注,2008年,国内外的多个大型社区和交互网站分别爆出CSRF漏洞,如:纽约时报,Metafilter,YouTube和百度。。。。而现在,互联网的许多站点仍对此毫无防备,以至于安全业界称CSRF为“沉睡的巨人”。

一、XSS(Cross Site Scripting)跨站脚本

  XSS其实就是Html的注入问题,攻击者的输入没有经过严格的控制进入了数据库,最终显示给来访的用户,导致可以在来访用户的浏览器里以浏览用户的身份执行Html代码。

数据流程为:攻击者的Html输入—>web程序—>进入数据库—>web程序—>用户浏览器。

跨站脚本,顾名思义,更多的情况下是注入一些js代码,实现站点影响或窃取用户信息等目的。

一般的攻击方式:

><script>alert(document.cookie)</script>
='><script>alert(document.cookie)</script>
"><script>alert(document.cookie)</script>
<script>alert(document.cookie)</script>
<script>alert(vulnerable)</script>

<script>alert('XSS')</script>
<img src="javascript:alert('XSS')">
<img src="http://xxx.com/yyy.png" onerror="alert('XSS')">
<div style="height:expression(alert('XSS'),1)" />(这个仅限 IE 有效)

通过在站点中可输入的文本区域,输入类似上述提到的js代码,若站点未对数据进行验证处理,脚本就会存入数据库,进而显示给其他用户,则其他用户将会受到影响。

而影响方式主要有几个:

  1. 如果是这种无聊恶意的

<script>alert(哈哈哈你关不掉我的~)</script>

用户打开相应站点则..关不掉..

或者恶意更改站点原数据

<script>
window.onload = function() {
    var links=document.getElementsByTagName("a");
    for(var i=0,j=links.length;i<j;i  ){
        links[i].href="http://ad.com/";
    }
};
</script>

 

  2.窃取cookie,或者更直接的是拿到sessionId(拿到该用户的登录凭证)

如果需要收集来自被攻击者的数据(如cookie或其他敏感信息),可以自行架设一个网站,让被攻击者通过JavaScript等方式把收集好的数据作为参数提交,随后以数据库等形式记录在攻击者自己的服务器上。 

而使用方式可以是暴力地直接跳转到恶意站点并附带参数,软暴力地则可以使用 img  link  script 标签src属性直接加载某个恶意站点,或者使用ajax暗地操刀。

  3.利用可被攻击的域受到其他域信任的特点,以受信任来源的身份请求一些平时不允许的操作(这个已经属于csrf范畴了)

 

一般的防御措施:

  1.永远不相信用户的输入。需要对用户的输入进行处理,只允许输入合法的值,其它值一概过滤掉。

某些情况下,我们不能对用户数据进行严格的过滤,那我们也需要对标签进行转换。

less-than character (<) &lt;
greater-than character (>) &gt;
ampersand character (&) &amp;
double-quote character (") &quot;
space character( ) &nbsp;
Any ASCII code character whose code is greater-than or equal to 0x80 &#<number>, where <number> is the ASCII character value.

比如用户输入:

<script>window.location.href=”http://www.baidu.com”;</script>,

保存后最终存储的会是:

&lt;script&gt;window.location.href=&quot;http://www.baidu.com&quot;&lt;/script&gt;

在展现时浏览器会对这些字符转换成文本内容显示,而不是一段可执行的代码。

许多语言都有提供对HTML的过滤:

PHP的htmlentities()或是htmlspecialchars()。
Python的cgi.escape()。
ASP的Server.HTMLEncode()。
ASP.NET的Server.HtmlEncode()或功能更强的Microsoft Anti-Cross Site Scripting Library
Java的xssprotect(Open Source Library)。
Node.js的node-validator。

  2.HttpOnly防止劫取Cookie

HttpOnly最早由微软提出,至今已经成为一个标准。浏览器将禁止页面的Javascript访问带有HttpOnly属性的Cookie。

目前主流浏览器都支持,HttpOnly解决是XSS后的Cookie支持攻击。

比如php代码的使用

<?php
header("Set-Cookie: cookie1=test1;");
header("Set-Cookie: cookie2=test2;httponly",false);

setcookie('cookie3','test3',NULL,NULL,NULL,NULL,false);
setcookie('cookie4','test4',NULL,NULL,NULL,NULL,true);
?>
<script>
    alert(document.cookie);
</script>

js只能读到没有HttpOnly标识的Cookie

图片 2

 

 

  3.1、简单级别CSRF攻击

  假设某游戏网站的虚拟币转账是采用GET方式进行操作的,样式如:

1 http://www.game.com/Transfer.php?toUserId=11&vMoney=1000

 

  此时恶意攻击者的网站也构建一个相似的链接:

  1、可以是采用图片隐藏,页面一打开就自动进行访问第三方文章:<img src='攻击链接'>

  2、也可以采用js进行相应的操作

http://www.game.com/Transfer.php?toUserId=20&vMoney=1000         #toUserID为攻击的账号ID

 

  1、假若客户端已经验证并登陆www.game.com网站,此时客户端浏览器保存了游戏网站的验证cookie

  2、客户端再tab另一个页面进行访问恶意攻击者的网站,并从恶意攻击者的网站构造的链接来访问游戏网站

  3、浏览器将会携带该游戏网站的cookie进行访问,刷一下就没了1000游戏虚拟币

1、简介

  CSRF的全名为Cross-site request forgery,它的中文名为跨站请求伪造(伪造跨站请求

  CSRF是一种夹持用户在已经登陆的web应用程序上执行非本意的操作的攻击方式。相比于XSS,CSRF是利用了系统对页面浏览器的信任,XSS则利用了系统对用户的信任。

回到顶部

CSRF攻击实例

听了这么多,可能大家还云里雾里,光听概念可能大家对于CSRF还是不够了解,下面我将举一个例子来让大家对CSRF有一个更深层次的理解。
我们先假设支付宝存在CSRF漏洞,我的支付宝账号是lyq,攻击者的支付宝账号是xxx。然后我们通过网页请求的方式 http://zhifubao.com/withdraw?account=lyq&amount=10000&for=lyq2 可以把我账号lyq的10000元转到我的另外一个账号lyq2上去。通常情况下,该请求发送到支付宝服务器后,服务器会先验证该请求是否来自一个合法的session并且该session的用户已经成功登陆。攻击者在支付吧也有账号xxx,他知道上文中的URL可以进行转账操作,于是他自己可以发送一个请求 http://zhifubao.com/withdraw?account=lyq&amount=10000&for=xxx 到支付宝后台。但是这个请求是来自攻击者而不是来自我lyq,所以不能通过安全认证,因此该请求作废。这时,攻击者xxx想到了用CSRF的方式,他自己做了个黄色网站,在网站中放了如下代码:http://zhifubao.com/withdraw?account=lyq&amount=10000&for=xxx 并且通过黄色链接诱使我来访问他的网站。当我禁不住诱惑时就会点了进去,上述请求就会从我自己的浏览器发送到支付宝,而且这个请求会附带我的浏览器中的cookie。大多数情况下,该请求会失败,因为支付宝要求我的认证信息,但是我如果刚访问支付宝不久,还没有关闭支付宝页面,我的浏览器中的cookie存有我的认证信息,这个请求就会得到响应
,从我的账户中转10000元到xxx账户里,而我丝毫不知情,攻击者拿到钱后逍遥法外。所以以后一定要克制住自己,不要随便打开别人的链接。

二、CSRF (Cross Site Request Fogery)跨站请求伪造

  XSS 是实现 CSRF 的诸多途径中的一条,但绝对不是唯一的一条。一般习惯上把通过 XSS 来实现的 CSRF 称为 XSRF。

    CSRF 顾名思义,是伪造请求,冒充用户在站内的正常操作。我们知道,绝大多数网站是通过 cookie 等方式辨识用户身份(包括使用服务器端 Session 的网站,因为 Session ID 也是大多保存在 cookie 里面的),再予以授权的。所以要伪造用户的正常操作,最好的方法是通过 XSS 或链接欺骗等途径,让用户在本机(即拥有身份 cookie 的浏览器端)发起用户所不知道的请求。 

要完成一次CSRF攻击,受害者必须依次完成两个步骤:

1.登录受信任网站A,并在本地生成Cookie。
2.在不登出A的情况下,访问危险网站B。

看到这里,你也许会说:“如果我不满足以上两个条件中的一个,我就不会受到CSRF的攻击”。

是的,确实如此,但你不能保证以下情况不会发生:
  1.你不能保证你登录了一个网站后,不再打开一个tab页面并访问另外的网站。
  2.你不能保证你关闭浏览器了后,你本地的Cookie立刻过期,你上次的会话已经结束。(事实上,关闭浏览器不能结束一个会话,但大多数人都会错误的认为关闭浏览器就等于退出登录/结束会话了……)
  3.上图中所谓的攻击网站,可能是一个存在其他漏洞的可信任的经常被人访问的网站。
   上面大概地讲了一下CSRF攻击的思想,下面我将用几个例子详细说说具体的CSRF攻击,这里我以一个银行转账的操作作为例子(仅仅是例子,真实的银行网站没这么傻:>)

示例1:
银行网站A,它以GET请求来完成银行转账的操作,如:

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

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

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

首先,你登录了银行网站A,然后访问危险网站B,噢,这时你会发现你的银行账户少了1000块……
    为什么会这样呢?原因是银行网站A违反了HTTP规范,使用GET请求更新资源。在访问危险网站B的之前,你已经登录了银行网站A,而B中的<img>以GET的方式请求第三方资源(这里的第三方就是指银行网站了,原本这是一个合法的请求,但这里被不法分子利用了),所以你的浏览器会带上你的银行网站A的Cookie发出Get请求,去获取资源“

结果银行网站服务器收到请求后,认为这是一个更新资源操作(转账操作),所以就立刻进行转账操作……

示例2:
为了杜绝上面的问题,银行决定改用POST请求完成转账操作。
银行网站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[&#039;toBankId&#039;] && isset($_REQUEST[&#039;money&#039;]))
    {
       buy_stocks($_REQUEST[&#039;toBankId&#039;], $_REQUEST[&#039;money&#039;]);
    }
?>

危险网站B,仍然只是包含那句HTML代码:

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

 和示例1中的操作一样,你首先登录了银行网站A,然后访问危险网站B,结果…..和示例1一样,你再次没了1000块~T_T,这次事故的原因是:银行后台使用了$_REQUEST去获取请求的数据,而$_REQUEST既可以获取GET请求的数据,也可以获取POST请求的数据,这就造成了在后台处理程序无法区分这到底是GET请求的数据还是POST请求的数据。在PHP中,可以使用$_GET和$_POST分别获取GET请求和POST请求的数据。在JAVA中,用于获取请求数据request一样存在不能区分GET请求数据和POST数据的问题。 

示例3:
    经过前面2个惨痛的教训,银行决定把获取请求数据的方法也改了,改用$_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>

 如果用户仍是继续上面的操作,很不幸,结果将会是再次不见1000块……因为这里危险网站B暗地里发送了POST请求到银行

    总结一下上面3个例子,CSRF主要的攻击模式基本上是以上的3种,其中以第1,2种最为严重,因为触发条件很简单,一个<img>就可以了,而第3种比较麻烦,需要使用JavaScript,所以使用的机会会比前面的少很多,但无论是哪种情况,只要触发了CSRF攻击,后果都有可能很严重。
    理解上面的3种攻击模式,其实可以看出,CSRF攻击是源于WEB的隐式身份验证机制!WEB的身份验证机制虽然可以保证一个请求是来自于某个用户的浏览器,但却无法保证该请求是用户批准发送的.

 

那有什么防御方法?

一般防御CSRF有三种方法,判断referer、验证码、token。

  1.判断 referer

根据HTTP协议,在HTTP头中有一个字段叫Referer,它记录了该HTTP请求的来源地址。

在通常情况下,访问一个安全受限页面的请求必须来自于同一个网站。

比如某银行的转账是通过用户访问. test域名开头的地址)。

而如果攻击者要对银行网站实施CSRF攻击,他只能在自己的网站构造请求,当用户通过攻击者的网站发送请求到银行时,该请求的Referer是指向攻击者的网站。

因此,要防御CSRF攻击,银行网站只需要对于每一个转账请求验证其Referer值,如果是以bank. test开头的域名,则说明该请求是来自银行网站自己的请求,是合法的。如果Referer是其他网站的话,就有可能是CSRF攻击,则拒绝该请求。

比如php的:

<?php
    if(eregi(”bank.test”, $_SERVER[’HTTP_REFERER’])) {
        do_something();
    } else {
        echo “Malicious Request!”;
    }
?> 

这个检测则会轻易的忽略掉来自某个攻击者伪造的HTTP Referer欺骗,

由于HTTP Referer是由客户端浏览器发送的,或者其他在恶意脚本中伪造HTTP头并发送的方法。攻击者可以使用如下代码是伪造无效的。

header(”Referer: bank.test”);

但缺点是并不是所有浏览器都支持referer头,或者一些flash的提交也不支持,所以存在着缺陷。

 

  2.验证码

另外一个解决这类问题的思路则是在用户提交的每一个表单中使用一个随机验证码,让用户在文本框中填写图片上的随机字符串,并且在提交表单后对其进行检测。

这个方法曾经在之前被人们放弃,这是由于验证码图片的使用涉及了一个被称为MHTML的Bug,可能在某些版本的微软IE中受影响。

而验证码的过度使用也会影响到用户体验。

  3.token

1)在请求地址中添加token并验证

CSRF攻击之所以能够成功,是因为攻击者可以伪造用户的请求,该请求中所有的用户验证信息都存在于Cookie中,因此攻击者可以在不知道这些验证信息的情况下直接利用用户自己的Cookie来通过安全验证。

由此可知,抵御CSRF攻击的关键在于:在请求中放入攻击者所不能伪造的信息,并且该信息不存在于Cookie之中。

鉴于此,系统开发者可以在HTTP请求中以参数的形式加入一个随机产生的token,并在服务器端建立一个拦截器来验证这个token,如果请求中没有token或者token内容不正确,则认为可能是CSRF攻击而拒绝该请求。

还是用php举例:

让我们从令牌值的生成开始:

<?php
function gen_token() {
// Generate the md5 hash of a randomized uniq id
$hash = md5(uniqid(rand(), true));
// Select a random number between 1 and 24 (32-8)
$n = rand(1, 24);
// Generate the token retrieving a part of the hash starting from
// the random N number with 8 of lenght
$token = substr($hash, $n, 8);
return $token;
}
?>

PHP函数uniqid()允许web开发者根据当前的时间(毫秒数)获得一个唯一的ID,这个唯一ID有利于生成一个不重复的数值。

我们检索相应ID值的MD5散列,而后我们从该散列中以一个小于24的数字为开始位置,选取8位字母、

返回的$token变量将检索一个8位长的随机令牌。

现在让我们生成一个Session令牌,在稍后的检查中我们会用到它。

<?php
function gen_stoken() {
// Call the function to generate the token
$token = gen_token();
// Destroy any eventually Session Token variable
destroy_stoken();
// Create the Session Token variable
session_register(STOKEN_NAME);
$_SESSION[STOKEN_NAME] = $token;
}
?>

在这个函数中我们调用gen_token()函数,并且使用返回的令牌将其值复制到一个新的$_SESSION变量。

现在让我们来看启动完整机制中为我们的表单生成隐藏输入域的函数:

<?php
function gen_input() {
// Call the function to generate the Session Token variable
gen_stoken();
// Generate the form input code
echo “<input type=”hidden” name=”" . FTOKEN_NAME . “”
value=”" . $_SESSION[STOKEN_NAME] . “”> “;
}
?>

我们可以看到,这个函数调用了gen_stoken()函数并且生成在WEB表单中包含隐藏域的HTML代码。

接下来让我们来看实现对隐藏域中提交的Session令牌的检测的函数:

<?php
function token_check() {
// Check if the Session Token exists
if(is_stoken()) {
// Check if the request has been sent
if(isset($_REQUEST[FTOKEN_NAME])) {
// If the Form Token is different from Session Token
// it’s a malicious request
if($_REQUEST[FTOKEN_NAME] != $_SESSION[STOKEN_NAME]) {
gen_error(1);
destroy_stoken();
exit();
} else {
destroy_stoken();
}
// If it isn’t then it’s a malicious request
} else {
gen_error(2);
destroy_stoken();
exit();
}
// If it isn’t then it’s a malicious request
} else {
gen_error(3);
destroy_stoken();
exit();
}
}
?>

这个函数检测了$_SESSION[STOKEN_NAME]和$_REQUEST[FTOKEN_NAME]的存在性(我使用了$ _REQUEST方法来使得GET和POST两种方式提交的表单变量均能够被接受),而后检测他们的值是否相同,因此判断当前表单提交是否是经过认证授权的。

这个函数的重点在于:在每次检测步骤结束后,令牌都会被销毁,并且仅仅在下一次表单页面时才会重新生成。

这些函数的使用方法非常简单,我们只需要加入一些PHP代码结构。

下面是Web表单:

<?php
session_start();
include(”functions.php”);
?>
<form method=”POST” action=”resolve.php”>
<input type=”text” name=”first_name”>
<input type=”text” name=”last_name”>
<!– Call the function to generate the hidden input –>
<? gen_input(); ?>
<input type=”submit” name=”submit” value=”Submit”>
</form>

下面是解决的脚本代码:

<?php
session_start();
include(”functions.php”);

// Call the function to make the check
token_check();

// Your code
…
?>

 

2)在HTTP头中自定义属性并验证

自定义属性的方法也是使用token并进行验证,和前一种方法不同的是,这里并不是把token以参数的形式置于HTTP请求之中,而是把它放到HTTP头中自定义的属性里。

通过XMLHttpRequest这个类,可以一次性给所有该类请求加上csrftoken这个HTTP头属性,并把token值放入其中。

这样解决了前一种方法在请求中加入token的不便,同时,通过这个类请求的地址不会被记录到浏览器的地址栏,也不用担心token会通过Referer泄露到其他网站。

 

  3.2、中级别CSRF攻击

  游戏网站负责人认识到了有被攻击的漏洞,将进行升级改进。

  将由链接GET提交数据改成了表单提交数据

//提交数据表单
<form action="./Transfer.php" method="POST">
    <p>toUserId: <input type="text" name="toUserId" /</p>
    <p>vMoney: <input type="text" name="vMoney" /></p>
    <p><input type="submit" value="Transfer" /></p>
</form>

 

  Transfer.php

1 <?php
2      session_start();
3      if (isset($_REQUEST['toUserId'] && isset($_REQUEST['vMoney']))  #验证
4      {
5           //相应的转账操作
6      }
7  ?>

 

  恶意攻击者将会观察网站的表单形式,并进行相应的测试。

  首先恶意攻击者采用( 

  那么此时游戏网站所做的更改没起到任何的防范作用,恶意攻击者只需要像上面那样进行攻击即可达到目的。

  总结:

  1、网站开发者的错误点在于没有使用$_POST进行接收数据。当$_REQUEST可以接收POST和GET发来的数据,因此漏洞就产生了。

2、CSRF攻击原理

下面为CSRF攻击原理图:

图片 3

由上图分析我们可以知道构成CSRF攻击是有条件的:

  1、客户端必须一个网站并生成cookie凭证存储在浏览器中

  2、该cookie没有清除,客户端又tab一个页面进行访问别的网站

回到顶部

CSRF原理

下面一张图简单阐述了CSRF的原理

图片 4

csrf原理

从上图可以看出,要完成一次CSRF攻击,受害者必须依次完成以下两个步骤:

  • 登录受信任网站A,并在本地生成Cookie。
  • 在不登出A的情况下,访问危险网站B。

看到这里,你也许会问:“如果我不满足以上两个条件中的一个,我就不会受到CSRF攻击”。是滴,确实如此,但是你不能保证以下情况不会发生:

  • 你不能保证你登录了一个网站之后,不再打开一个tab页面并访问其它的网站(黄网)。
  • 你不能保证你关闭浏览器之后,你本地的Cookie立刻过期,你上次的会话已经结束。
  • 上述中所谓的攻击网站,可能就是一个钓鱼网站或者黄色网站。

  3.3、高级别CSRF攻击

  这一次,游戏网站开发者又再一次认识到了错误,将进行下一步的改进与升级,将采用POST来接收数据

  Transfer.php

1 <?php
2      session_start();
3      if (isset($_POST['toUserId'] && isset($_POST['vMoney']))  #验证
4      {
5           //相应的转账操作
6      }
7  ?>

 

  此时恶意攻击者就没有办法进行攻击了么?那是不可能的。

  恶意攻击者根据游戏虚拟币转账表单进行伪造了一份一模一样的转账表单,并且嵌入到iframe中

嵌套页面:(用户访问恶意攻击者主机的页面,即tab的新页面)

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>攻击者主机页面</title>
    <script type="text/javascript">
    function csrf()
    {
        window.frames['steal'].document.forms[0].submit();
    }
    </script>
</head>
<body onload="csrf()">
<iframe name="steal" display="none" src="./xsrf.html">
</iframe>
</body>
</html>

 

表单页面:(csrf.html)

<!DOCTYPE html>
<html>
<head>
    <title>csrf</title>
</head>
<body>
<form display="none" action="http://www.game.com/Transfer.php" method="post" >
    <input type="hidden" name="toUserID" value="20">
    <input type="hidden" name="vMoney" value="1000">
</form>
</body>
</html>

  客户端访问恶意攻击者的页面一样会遭受攻击。

总结:

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

 

3、CSRF例子与分析

  我们就以游戏虚拟币转账为例子进行分析

回到顶部

CSRF如何防御

4、CSRF防御方法

  服务器端防御:

  1、重要数据交互采用POST进行接收,当然是用POST也不是万能的,伪造一个form表单即可破解

  2、使用验证码,只要是涉及到数据交互就先进行验证码验证,这个方法可以完全解决CSRF。但是出于用户体验考虑,网站不能给所有的操作都加上验证码。因此验证码只能作为一种辅助手段,不能作为主要解决方案。

  3、验证HTTP Referer字段,该字段记录了此次HTTP请求的来源地址,最常见的应用是图片防盗链。PHP中可以采用APache URL重写规则进行防御,可参考:

  4、为每个表单添加令牌token并验证

(可以使用cookie或者session进行构造。当然这个token仅仅只是针对CSRF攻击,在这前提需要解决好XSS攻击,否则这里也将会是白忙一场【XSS可以偷取客户端的cookie】) 

  CSRF攻击之所以能够成功,是因为攻击者可以伪造用户的请求,该请求中所有的用户验证信息都存在于Cookie中,因此攻击者可以在不知道这些验证信息的情况下直接利用用户自己的Cookie来通过安全验证。由此可知,抵御CSRF攻击的关键在于:在请求中放入攻击者所不能伪造的信息,并且该信息不存在于Cookie之中。

  鉴于此,我们将为每一个表单生成一个随机数秘钥,并在服务器端建立一个拦截器来验证这个token,如果请求中没有token或者token内容不正确,则认为可能是CSRF攻击而拒绝该请求。

  由于这个token是随机不可预测的并且是隐藏看不见的,因此恶意攻击者就不能够伪造这个表单进行CSRF攻击了。

  要求:

  1、要确保同一页面中每个表单都含有自己唯一的令牌

  2、验证后需要删除相应的随机数

构造令牌类Token.calss.php

 1 <?php
 2 class Token
 3 {
 4     /**
 5     * @desc 获取随机数
 6     *
 7     * @return string 返回随机数字符串
 8     */
 9     private function getTokenValue()
10     {
11         return md5(uniqid(rand(), true).time());
12     }
13     
14     /**
15     * @desc 获取秘钥
16     *
17     * @param $tokenName string | 与秘钥值配对成键值对存入session中(标识符,保证唯一性)
18     *
19     * @return array 返回存储在session中秘钥值
20     */
21     public function getToken($tokenName)
22     {
23         $token['name']=$tokenName;      #先将$tokenName放入数组中
24         session_start();
25         if(@$_SESSION[$tokenName])      #判断该用户是否存储了该session
26         {                               #是,则直接返回已经存储的秘钥
27             $token['value']=$_SESSION[$tokenName];
28             return $token;
29         }
30         else                            #否,则生成秘钥并保存
31         {
32             $token['value']=$this->getTokenValue();
33             $_SESSION[$tokenName]=$token['value'];
34             return $token;
35         }
36     }
37 
38 }
39 #测试
40 $csrf=new Token();
41 $name='form1';
42 $a=$csrf->getToken($name);
43 echo "<pre>";
44 print_r($a);
45 echo "</pre>";
46 echo "<pre>";
47 print_r($_SESSION);
48 echo "</pre>";die;
49 
50 ?> 

 表单中使用:

 1 <?php
 2           session_start();
 3           include(”Token.class.php”);
 4           $token=new Token();
 5           $arr=$token->getToken(‘transfer’);    #保证唯一性(标识符)
 6 ?>
 7  <form method=”POST” action=”./transfer.php”>
 8           <input type=”text” name=”toUserId”>
 9           <input type=”text” name=”vMoney”>
10           <input type="hidden" name="<?php echo $arr['name'] ?>"  value="<?php echo $arr['value']?>" >
11           <input type=”submit” name=”submit” value=”Submit”>
12  </from>

 验证:

 1 <?php
 2 #转账表单验证
 3 session_start();
 4 if($_POST['transfer']==$_SESSION['transfer'])       #先检验秘钥
 5 {
 6     unset($_SESSION['transfer']);    #删除已经检验的存储秘钥
 7     if ( &&isset($_POST['toUserId'] && isset($_POST['vMoney']))  #验证
 8     {
 9          //相应的转账操作
10     }
11 }
12 else
13 {
14     return false;
15 }
16 ?>

 1 <?php
 2 #转账表单验证
 3 session_start();
 4 if($_POST['transfer']==$_SESSION['transfer'])       #先检验秘钥
 5 {
 6     unset($_SESSION['transfer']);    #删除已经检验的存储秘钥
 7     if ( &&isset($_POST['toUserId'] && isset($_POST['vMoney']))  #验证
 8     {
 9          //相应的转账操作
10     }
11 }
12 else
13 {
14     return false;
15 }
16 ?>

该方法套路:

  1. 用户访问某个表单页面。

2. 服务端生成一个Token,放在用户的Session中,或者浏览器的Cookie中。【这里已经不考虑XSS攻击】

  1. 在页面表单附带上Token参数。

  2. 用户提交请求后, 服务端验证表单中的Token是否与用户Session(或Cookies)中的Token一致,一致为合法请求,不是则非法请求。

 

  3.1、简单级别CSRF攻击

  假设某游戏网站的虚拟币转账是采用GET方式进行操作的,样式如:

1 http://www.game.com/Transfer.php?toUserId=11&vMoney=1000

  此时恶意攻击者的网站也构建一个相似的链接:

  1、可以是采用图片隐藏,页面一打开就自动进行访问第三方文章:<img src='攻击链接'>

  2、也可以采用js进行相应的操作

http://www.game.com/Transfer.php?toUserId=20&vMoney=1000         #toUserID为攻击的账号ID

  1、假若客户端已经验证并登陆www.game.com网站,此时客户端浏览器保存了游戏网站的验证cookie

  2、客户端再tab另一个页面进行访问恶意攻击者的网站,并从恶意攻击者的网站构造的链接来访问游戏网站

  3、浏览器将会携带该游戏网站的cookie进行访问,刷一下就没了1000游戏虚拟币

回到顶部

验证HTTP Referer字段

根据HTTP协议,在HTTP头部中有一个Referer字段,它记录了该HTTP请求所在的地址,表示HTTP请求从那个页面发出的。比如当你访问 http://zhifubao.com/withdraw?account=lyq&amount=10000&for=xxx ,用户必须先登录支付宝网站,然后通过点击页面的的按钮来触发转账事件。此时,转账请求的Referer值就是转账页面所在的URL,通常是以zhifubao.com域名开头的地址。如果攻击者要实行CSRF攻击,那么他只能在自己的站点构造请求,此时Referer的值就指向黑客自己的网站。因此要防御CSRF攻击,支付宝只需要对每一个转账请求验证其Referer值,如果是以zhifubao.com开头的域名,则是合法请求,相反,则是非法请求并拒绝。
这种方法的好处就是简单易行,只需要在后台添加一个拦截器来检查Referer即可。然而这种办法并不是万无一失,Referer的值是由浏览器提供的,一些低级的浏览器可以通过某种方式篡改Referer的值,这就给了攻击者可乘之机;而一些高级浏览器处于安全考虑,可以让用户设置发送HTTP请求时不再提供Referer值,这样当他们正常访问支付宝网站时,因为没有提供Referer值而被误认为CERF攻击,拒绝访问。实际应用中通常采用第二种方法来防御CSRF攻击。

5、参考文献

1. 《浅谈CSRF攻击方式》

2. 《Web安全之CSRF攻击》

 

(以上是自己的一些见解,若有不足或者错误的地方请各位指出)

 作者:那一叶随风   

 原文地址:

 声明:本博客文章为原创,只代表本人在工作学习中某一时间内总结的观点或结论。转载时请在文章页面明显位置给出原文链接

 

  3.2、中级别CSRF攻击

  游戏网站负责人认识到了有被攻击的漏洞,将进行升级改进。

  将由链接GET提交数据改成了表单提交数据

图片 5

//提交数据表单
<form action="./Transfer.php" method="POST">    <p>toUserId: <input type="text" name="toUserId" /</p>    <p>vMoney: <input type="text" name="vMoney" /></p>    <p><input type="submit" value="Transfer" /></p></form>

图片 6

  Transfer.php

图片 7

1 <?php2      session_start();3      if (isset($_REQUEST['toUserId'] && isset($_REQUEST['vMoney']))  #验证4      {5           //相应的转账操作6      }7  ?>

图片 8

  恶意攻击者将会观察网站的表单形式,并进行相应的测试。

  首先恶意攻击者采用(

  那么此时游戏网站所做的更改没起到任何的防范作用,恶意攻击者只需要像上面那样进行攻击即可达到目的。

  总结:

  1、网站开发者的错误点在于没有使用$_POST进行接收数据。当$_REQUEST可以接收POST和GET发来的数据,因此漏洞就产生了。

回到顶部

添加token验证

CSRF攻击之所以能够成功,是因为攻击者可以完全伪造用户的请求,该请求中所有的用户验证信息都存在cookie中,因此攻击者可以在不知道这些验证信息的情况下直接利用用户自己的cookie来通过安全验证。要防止CSRF,关键在于在请求中放入黑客所不能伪造的信息,并且该信息不存在于cookie之中。可以在HTTP请求中以参数的形式加入一个随机产生的token,并在服务器建立一个拦截器来验证这个token,如果请求中没有token或者token不正确,则认为可能是CSRF攻击而拒绝该请求。
现在业界一致的做法就是使用Anti CSRF Token来防御CSRF。

  • 用户访问某个表单页面。
  • 服务端生成一个Token,放在用户的Session中,或者浏览器的Cookie中。
  • 在页面表单附带上Token参数。
  • 用户提交请求后,服务端验证表单中的Token是否与用户Session(或Cookies)中的Token一致,一致为合法请求,不是则非法请求。

这个Token值必须是随机的,不可预测的。由于Token的存在,攻击者无法再构造一个带有合法Token的请求实施CSRF攻击。另外使用Token应注意Token的保密性,尽量把敏感操作由GET改成POST,以form或者AJAX形式提交,避免Token泄露。

  3.3、高级别CSRF攻击

  这一次,游戏网站开发者又再一次认识到了错误,将进行下一步的改进与升级,将采用POST来接收数据

  Transfer.php

图片 9

1 <?php2      session_start();3      if (isset($_POST['toUserId'] && isset($_POST['vMoney']))  #验证4      {5           //相应的转账操作6      }7  ?>

图片 10

  此时恶意攻击者就没有办法进行攻击了么?那是不可能的。

  恶意攻击者根据游戏虚拟币转账表单进行伪造了一份一模一样的转账表单,并且嵌入到iframe中

嵌套页面:(用户访问恶意攻击者主机的页面,即tab的新页面)

图片 11

<!DOCTYPE html><html><head>    <meta charset="utf-8">    <title>攻击者主机页面</title>    <script type="text/javascript">    function csrf()    {        window.frames['steal'].document.forms[0].submit();    }    </script></head><body onload="csrf()"><iframe name="steal" display="none" src="./xsrf.html"></iframe></body></html>

图片 12

表单页面:(csrf.html)

图片 13

<!DOCTYPE html><html><head>    <title>csrf</title></head><body><form display="none" action="http://www.game.com/Transfer.php" method="post" >    <input type="hidden" name="toUserID" value="20">    <input type="hidden" name="vMoney" value="1000"></form></body></html>

图片 14

  客户端访问恶意攻击者的页面一样会遭受攻击。

总结:

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

回到顶部

验证码

验证码,强制用户必须与应用进行交互,才能完成最终请求。通常情况下,验证码能够很好的遏制CSRF攻击。但是出于用户体验考虑,网站不能给所有的操作都加上验证码。因此验证码只能作为一种辅助手段。

4、CSRF防御方法

  服务器端防御:

  1、重要数据交互采用POST进行接收,当然是用POST也不是万能的,伪造一个form表单即可破解

  2、使用验证码,只要是涉及到数据交互就先进行验证码验证,这个方法可以完全解决CSRF。但是出于用户体验考虑,网站不能给所有的操作都加上验证码。因此验证码只能作为一种辅助手段,不能作为主要解决方案。

  3、验证HTTP Referer字段,该字段记录了此次HTTP请求的来源地址,最常见的应用是图片防盗链。PHP中可以采用APache URL重写规则进行防御,可参考:

  4、为每个表单添加令牌token并验证

(可以使用cookie或者session进行构造。当然这个token仅仅只是针对CSRF攻击,在这前提需要解决好XSS攻击,否则这里也将会是白忙一场【XSS可以偷取客户端的cookie】)

  CSRF攻击之所以能够成功,是因为攻击者可以伪造用户的请求,该请求中所有的用户验证信息都存在于Cookie中,因此攻击者可以在不知道这些验证信息的情况下直接利用用户自己的Cookie来通过安全验证。由此可知,抵御CSRF攻击的关键在于:在请求中放入攻击者所不能伪造的信息,并且该信息不存在于Cookie之中。

  鉴于此,我们将为每一个表单生成一个随机数秘钥,并在服务器端建立一个拦截器来验证这个token,如果请求中没有token或者token内容不正确,则认为可能是CSRF攻击而拒绝该请求。

  由于这个token是随机不可预测的并且是隐藏看不见的,因此恶意攻击者就不能够伪造这个表单进行CSRF攻击了。

  要求:

  1、要确保同一页面中每个表单都含有自己唯一的令牌

  2、验证后需要删除相应的随机数

构造令牌类Token.calss.php

图片 15

 1 <?php 2 class Token 3 { 4     /** 5     * @desc 获取随机数 6     * 7     * @return string 返回随机数字符串 8     */ 9     private function getTokenValue()10     {11         return md5(uniqid(rand(), true).time;12     }13     14     /**15     * @desc 获取秘钥16     *17     * @param $tokenName string | 与秘钥值配对成键值对存入session中(标识符,保证唯一性)18     *19     * @return array 返回存储在session中秘钥值20     */21     public function getToken($tokenName)22     {23         $token['name']=$tokenName;      #先将$tokenName放入数组中24         session_start();25         if(@$_SESSION[$tokenName])      #判断该用户是否存储了该session26         {                               #是,则直接返回已经存储的秘钥27             $token['value']=$_SESSION[$tokenName];28             return $token;29         }30         else                            #否,则生成秘钥并保存31         {32             $token['value']=$this->getTokenValue();33             $_SESSION[$tokenName]=$token['value'];34             return $token;35         }36     }37 38 }39 #测试40 $csrf=new Token();41 $name='form1';42 $a=$csrf->getToken($name);43 echo "<pre>";44 print_r($a);45 echo "</pre>";46 echo "<pre>";47 print_r($_SESSION);48 echo "</pre>";die;49 50 ?>

图片 16

表单中使用:

图片 17

 1 <?php 2           session_start(); 3           include(”Token.class.php”); 4           $token=new Token(); 5           $arr=$token->getToken(‘transfer’);    #保证唯一性 6 ?> 7  <form method=”POST” action=”./transfer.php”> 8           <input type=”text” name=”toUserId”> 9           <input type=”text” name=”vMoney”>10           <input type="hidden" name="<?php echo $arr['name'] ?>"  value="<?php echo $arr['value']?>" >11           <input type=”submit” name=”submit” value=”Submit”>12  </from>

图片 18

验证:

图片 19

 1 <?php 2 #转账表单验证 3 session_start(); 4 if($_POST['transfer']==$_SESSION['transfer'])       #先检验秘钥 5 { 6     unset($_SESSION['transfer']);    #删除已经检验的存储秘钥 7     if ( &&isset($_POST['toUserId'] && isset($_POST['vMoney']))  #验证 8     { 9          //相应的转账操作10     }11 }12 else13 {14     return false;15 }16 ?>

图片 20图片 21

 1 <?php 2 #转账表单验证 3 session_start(); 4 if($_POST['transfer']==$_SESSION['transfer'])       #先检验秘钥 5 { 6     unset($_SESSION['transfer']);    #删除已经检验的存储秘钥 7     if ( &&isset($_POST['toUserId'] && isset($_POST['vMoney']))  #验证 8     { 9          //相应的转账操作10     }11 }12 else13 {14     return false;15 }16 ?>

图片 22

该方法套路:

  1. 用户访问某个表单页面。

2. 服务端生成一个Token,放在用户的Session中,或者浏览器的Cookie中。【这里已经不考虑XSS攻击】

  1. 在页面表单附带上Token参数。

  2. 用户提交请求后, 服务端验证表单中的Token是否与用户Session中的Token一致,一致为合法请求,不是则非法请求。

回到顶部

尽量使用POST,限制GET

GET接口能够直接将请求地址暴露给攻击者,所以要防止CSRF一定最好不要用GET。当然POST并不是万无一失,攻击者只需要构造一个form表单就可以,但需要在第三方页面做,这样就增加了暴露的可能性。

CS福睿斯F攻击与堤防,跨站供给伪造。5、参考文献

  1. 《浅谈CSRF攻击方式》

  2. 《Web安全之CSRF攻击》

(以上是自己的一些见解,若有不足或者错误的地方请各位指出)

原文地址:

声明:本博客文章为原创,只代表本人在工作学习中某一时间内总结的观点或结论。转载时请在文章页面明显位置给出原文链接

在HTTP头部添加自定义属性

这种方法也是使用token并验证,但是它是把token放在HTTP请求头部中。通过使用AJAX我们可以在我们的请求头部中添加我们的自定义属性,但是这种方法要求我们将整个站的请求全部改成AJAX,如果是新站还好,老站的话无疑是需要重写整个站点的,这是很不可取的。

好了,CSRF讲完了,下篇文章我们介绍XSS跨站脚本攻击。

本文由澳门新浦京娱乐场网站发布于www.146.net,转载请注明出处:CS福睿斯F攻击与堤防,跨站供给伪造