安全性测试入门 (三):CSRF 跨站请求伪造攻击和防护

本篇继续对于安全性测试话题,结合DVWA进行研习。php

CSRF(Cross-site request forgery):跨站请求伪造html

1. 跨站请求伪造攻击

CSRF则经过假装成受信任用户的请求来利用受信任的网站,诱使用户使用攻击性网站,从而达到直接劫持用户会话的目的。mysql

因为如今的主流浏览器好比火狐和谷歌,都倾向于使用单个进程来管理用户会话(好比咱们在FF和Chrome中,当要访问一个新页面时,一般是经过新增浏览器页面来达到的,而不是新开一个浏览器客户端进程),因此攻击者就能够经过用户新开的页面来劫持用户的已有cookie等关键信息。
常见的攻击形式,是经过邮件,QQ等即时聊天工具,给被攻击对象发送伪造连接。被攻击者一旦访问了该恶意连接,攻击即生效。sql

DVWA的相应模块中,使用一个密码修改功能来展现了CSRF攻击的可能性。浏览器

构造攻击

咱们观察上述密码修改功能所触发的请求:安全

能够看到这个请求很是之简单,所需传递的只有三个参数服务器

  • password_new
  • password_conf
  • change

那么若是攻击者直接构造这样一条请求交给被攻击者去执行会怎么样?
好比我构造这样一条URL:cookie

若是被攻击者傻呵呵的点击了,那么恭喜他,他的密码就已经被我改为"attackerpw"了。
固然了,这个连接的攻击意图过于明显了,攻击者还能够经过假装一下这个连接,从而达到神不知鬼不觉的目的。session

  • 好比经过缩短连接服务:

  • 好比经过构建一个带有攻击代码的页面,诱使被攻击者访问:

上图看起来就是个不明因此的网页?但实际上访问到网页的时候红框部分的攻击代码就已经生效了!工具

2.CSRF的防护

下面咱们看一看DVWA是如何防护跨站脚本伪造的:
Medium级别防护

<?php

if( isset( $_GET[ 'Change' ] ) ) {
    // Checks to see where the request came from
    if( stripos( $_SERVER[ 'HTTP_REFERER' ] ,$_SERVER[ 'SERVER_NAME' ]) !== false ) {
        // 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>' );

            // Feedback for the user
            $html .= "<pre>Password Changed.</pre>";
        }
        else {
            // Issue with passwords matching
            $html .= "<pre>Passwords did not match.</pre>";
        }
    }
    else {
        // Didn't come from a trusted source
        $html .= "<pre>That request didn't look correct.</pre>";
    }

    ((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);
}

?>

能够看到中级防护机制,关键在于如下部分:

即判断请求来源,若是相似修改密码的这种请求来自于未知第三方地址,那么则不执行修改逻辑。
这是不难绕过的,只需在攻击页面中加入HTTP_REFERER并使其与被攻击server一致便可。

High级别防护

<?php

if( isset( $_GET[ 'Change' ] ) ) {
    // Check Anti-CSRF token
    checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );

    // 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>' );

        // Feedback for the user
        $html .= "<pre>Password Changed.</pre>";
    }
    else {
        // Issue with passwords matching
        $html .= "<pre>Passwords did not match.</pre>";
    }

    ((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);
}

// Generate Anti-CSRF token
generateSessionToken();

?>

嘞了嘞了,耳熟能详的Token他来了:

用户每次访问页面,服务器会随机生成一个Token,至关于用户的身份牌。只有身份牌验证经过,功能逻辑才执行。
Token是如今很流行的令牌机制,可是他也是一种比较简单的机制,绝非无懈可击。接口测试作的多的话应该能感觉到,咱们接口测试中常常会对Token作传递处理。
实际token就在网页元素里面,以下图所示

咱们经过抓包、爬虫、元素定位等方式彻底能够获取到,传递到攻击页面中 - 固然这会须要必定的代码编写量了!

Impossible级别

DVWA提供的最高级别防护机制,说穿了很是简单,即修改密码前,强制要求用户输入旧密码。
若是不知道旧密码,则不管怎样也没法修改用户密码。

3. CSRF防护能力测试

结合着上述讨论,一样咱们能够总结一下这一安全测试点的测试思路。

对于CSRF跨站脚本伪造攻击咱们能够作:

  • 渗透性测试: 扮演攻击者的角色,利用已知的攻击手段尝试跨站脚本伪造,好比本身构造请求和简单的页面进行攻击。

  • 运行时测试: 实际就是功能测试,咱们能够经过验证系统是否存在相应的防护功能:好比token机制,请求来源验证等。

  • 代码审计: 了解了CSRF的几个级别的防护机制,那么就能够经过代码审计的方式来肯定被测应用的后台逻辑有无相应防护机制。

还有一个问题在于,什么样的系统功能点多是CSRF攻击的敏感区域呢?

从本文的例子中咱们能够看到,当系统以一种简单的请求方式实现某种功能时,CSRF就存在劫持用户会话的可能性。那么这就要求测试人员可以敏锐的发现相似的系统特性区域,而且予以判断,是否有可能被会话劫持。

好比在一个购物平台中,订单的提交流程若是过于简单,一个简单的get请求就能实现下单功能(从这一点来讲,get请求就不该用于处理敏感操做,发现这种状况就是你测试的点!),那么你就能够摩拳擦掌,考虑来一次渗透测试了。

从这个角度来讲,对于安全性测试,知识和技术的累积是一方面,而敏锐的思惟能力特别是逆向思惟能力更加剧要!

相关文章
相关标签/搜索