0x01、什么是CSRF

CSRF(Cross Site Request Forgery),中文名称跨站点请求伪造 , 跟XSS攻击一样,存在巨大的危害性 。利用csrf,攻击者可以盗用你的身份,以你的名义发送恶意请求。 你的名义发送邮件、发消息,盗取你的账号,添加系统管理员,甚至于购买商品、虚拟货币转账等。

0x02、CSRF攻击原理

1、Tom登录某银行网站,于是浏览器生成了Tom在该银行的的身份验证信息。

2、Jerry利用Sns.com服务器将伪造的转账请求包含在帖子中,并把帖子链接发给了Tom。

3、Tom在银行网站保持登录的情况下浏览帖子

4、这时Tom就在不知情的情况下将伪造的转账请求连同身份认证信息发送到银行网站。

5、银行网站看到身份认证信息,认为请求是Tom的合法操作

之后,银行网站会报据Tom的权限来处理Jerry所发起的恶意请求,这样Jerry就达到了伪造Tom的身份请求银行网站给自己转账的目的。

在此过程中受害者Tom只需要做下面两件事情,攻击者Jerry就能够完成CSRF攻击:

  • 登录受信任银行网站,并生成身份验证信息;

  • 在不登出银行网站(清除身份验证信息)的情况下,访问恶意站点Sns.com。

很多情况下所谓的恶意站点,很有可能是一个存在其他漏洞(如XSS) 的受信任且被很多人访问的站点,这样,普通用户可能在不知不觉中便成为了受害者。

0x03、CSRF攻击分类

CSRF漏洞一般分为站外和站内两种类型。

CSRF站内类型的漏洞在一定程度上是由于程序员滥用$_REQUEST类变量造成的,一些敏感的操作本来是要求用户从表单提交发起POST请求传参给程序,但是由于使用了$_REQUEST等变量,程序也接收GET请求传参,这样就给攻击者使用CSRF攻击创造了条件,一般攻击者只要把预测好的请求参数放在站内一个贴子或者留言的图片链接里,受害者浏览了这样的页面就会被强迫发起请求。

CSRF站外类型的漏洞其实就是传统意义上的外部提交数据问题,一般程序员会考虑给一些留言评论等的表单加上水印以防止SPAM问题,但是为了用户的体验性,一些操作可能没有做任何限制,所以攻击者可以先预测好请求的参数,在站外的Web页面里编写javascript脚本伪造文件请求或和自动提交的表单来实现GET、POST请求,用户在会话状态下点击链接访问站外的Web页面,客户端就被强迫发起请求。

0x04、CSRF漏洞检测

检测CSRF漏洞是一项比较繁琐的工作,最简单的方法就是抓取一个正常请求的数据包,去掉Refexex字段后再重新提交,如果该提交还有效,那么基本上可以确定存在CSRF漏洞。

随着对CSRF漏洞研究的不断深入,不断涌现出一些专[门针对CSRF漏洞进行检测的工具,如CSRFTester, CSRF Request Builder等。

以CSRFTester工具为例,CSRF漏洞检测工具的测试原理如下:使用CSRFTester进行测试时,首先需要抓取我们在浏览器中访问过的所有链接以及所有的表单等信息,然后通过在CSRFTester中修改相应的表单等信息,重新提交,这相当于一次伪造客户端请求。如果修改后的测试请求成功被网站服务器接受,则说明存在CSRF漏洞,当然此款工具也可以被用来进行CSRF攻击。

0x05、CSRF攻击实例

DVWA-CSRF

low级别

查看源代码:

<?php

if( isset( $_GET[ 'Change' ] ) ) {
    // Get input
    $pass_new  = $_GET[ 'password_new' ];
    $pass_conf = $_GET[ 'password_conf' ];

    // Do the passwords match?
    if( $pass_new == $pass_conf ) {
        // They do!
        $pass_new = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"],  $pass_new ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));
        $pass_new = md5( $pass_new );

        // Update the database
        $insert = "UPDATE `users` SET password = '$pass_new' WHERE user = '" . dvwaCurrentUser() . "';";
        $result = mysqli_query($GLOBALS["___mysqli_ston"],  $insert ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' );
点击收藏 | 2 关注 | 3
登录 后跟帖