DVWA:Cross Site Request Forgery (CSRF)源码解析

文章详细介绍了DVWA(DamnVulnerableWebApplication)中关于CSRF(跨站请求伪造)的四种不同安全级别(Low,Medium,High,Impossible)的源代码实现,包括密码更改过程和相应的防护措施,如验证Referer头和使用CSRF令牌来防止未授权的修改操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

DVWA:Cross Site Request Forgery (CSRF)源码解析

简介

CSRF:跨站请求伪造(英语:Cross-site request forgery),也被称为 one-click attack 或者 session riding,通常缩写为 CSRF 或者 XSRF, 是一种挟制用户在当前已登录的Web应用程序上执行非本意的操作的攻击方法。

源码解析

Low CSRF Source

无验证可随意更改密码

<?php

if( isset( $_GET[ 'Change' ] ) ) {  //如果利用了Change进行了传值
    // 获取输入的值
    $pass_new  = $_GET[ 'password_new' ];   //获取参数password_new对应的值存储到pass_new中
    $pass_conf = $_GET[ 'password_conf' ];  //获取参数password_conf对应的值存储到pass_conf中

    // 看密码和确认密码(pass_new和pass_conf)是否相同
    if( $pass_new == $pass_conf ) {
        // 三元表达式(数据库连接存在?将新密码进行转义:报错)
        //如果数据库连接存在则将新密码进行转义中否则报错
        $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 );   //将密码用ma5进行加密
        /* 数据库中存储的密码实际为密码的md5值,用于防止密码的泄露*/

        // 更新数据库
        $insert = "UPDATE `users` SET password = '$pass_new' WHERE user = '" . dvwaCurrentUser() . "';";    //将计算好的MD5值添加到当前用户
        // 执行sql语句,如果失败报错输出
        $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>' );

        // 给用户回显
        echo "<pre>Password Changed.</pre>";
    }
    else {
        // 如果密码和确认密码值不一样则告诉用户
        echo "<pre>Passwords did not match.</pre>";
    }
        // 关闭数据库连接
    ((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);
}

?> 

Medium CSRF Source

添加了对服务器进行验证,对本地搭建的DVWA靶场无效

在这里插入图片描述
在这里插入图片描述


<?php

if( isset( $_GET[ 'Change' ] ) ) {  // 如果前端用了get方法进行传参
    // 查看请求的来源
    // 查看前端请求中是否存在服务器名称,如果存在则继续进行,详见下方补充
    if( stripos( $_SERVER[ 'HTTP_REFERER' ] ,$_SERVER[ 'SERVER_NAME' ]) !== false ) {
        // 获得输入的值
        $pass_new  = $_GET[ 'password_new' ];
        $pass_conf = $_GET[ 'password_conf' ];

        // 查看密码和确认密码是否一样
        if( $pass_new == $pass_conf ) {
            //如果一样
        // 三元表达式(数据库连接存在?将新密码进行转义:报错)
        //如果数据库连接存在则将新密码进行转义中否则报错
            $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 );   //将密码用md5进行加密

            // 更新数据库信息
            $insert = "UPDATE `users` SET password = '$pass_new' WHERE user = '" . dvwaCurrentUser() . "';";    //将用户密码和当前用户添加进sql语句中
            // 执行sql语句,如果失败报错输出
            $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>' );

            // 给用户修改成功的回显
            echo "<pre>Password Changed.</pre>";
        }
        else {
            // 如果不一样给用户回显
            echo "<pre>Passwords did not match.</pre>";
        }
    }
    else {
        // 如果前端请求中不存在服务器名称,则这不是一个可信的源,给出回显
        echo "<pre>That request didn't look correct.</pre>";
    }
    // 关闭数据库连接
    ((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);
}


/*
补充:
    1. function stripos($haystack, $needle, $offset = 0): bool|int { },
        该函数用于在查询在变量"haystack"所存的字符串中,
        不分大小写地查询在变量"needle"中所存字符串是否存在,
        若存在返回第一次出现的位置,
        若不存在返回false,offset为偏移量,默认为0,可省略
        $haystack:样本字符串
        $needle:要匹配的字符串
        $offset:偏移量
    2. $_SERVER 是一个在PHP中预定义的超全局变量,用于存储关于服务器和请求的信息
*/

?>

High CSRF Source

设置了防CSRF令牌,用户没错方位页面时服务器都会生成一个令牌,当数据传输的后端时会验证该令牌

  1. 打开burpsuite下载CSRF Token Tracker
    在这里插入图片描述2. 进行抓包
    请添加图片描述
  2. 将令牌名称和令牌内容添加到CSRF Token Tracker中,(这里数据包让我放了,找了张别的意思是这个意思)
    在这里插入图片描述
    在这里插入图片描述
  3. 将数据包发送到重发器中修改传参进行发送,发现可成功修改密码
    ![在这里插入图片描述](https://img-blog.csdnimg.cn/e539b664c1b448e991f4c18818170732.png
<?php

if( isset( $_GET[ 'Change' ] ) ) {
    // 查看防CSRF令牌
    // 查看Request中是否存在"user_token"和Session中是否有"session_token",范围为index.php
    checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );

    // 获取前端输入的值
    $pass_new  = $_GET[ 'password_new' ];
    $pass_conf = $_GET[ 'password_conf' ];

    // 查看密码和确认密码是否一致
    if( $pass_new == $pass_conf ) {
        // 如果一致
        // 三元表达式(数据库连接存在?将新密码进行转义:报错)
        //如果数据库连接存在则将新密码进行转义中否则报错
        $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 );   // 将密码进行md5加密

        // 更新数据库
        $insert = "UPDATE `users` SET password = '$pass_new' WHERE user = '" . dvwaCurrentUser() . "';";     //将用户密码和当前用户添加进sql语句中
        // 执行sql语句,失败则报错
        $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>' );

        // 给用户回显
        echo "<pre>Password Changed.</pre>";
    }
    else {
        // 如果密码和确认密码不一致则给用户回显
        echo "<pre>Passwords did not match.</pre>";
    }
    //关闭数据库连接资源
    ((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);
}

// 生成防CSRF令牌
generateSessionToken();

?>

Impossible CSRF Source

<?php

if( isset( $_GET[ 'Change' ] ) ) {
        // 查看防CSRF令牌
    // 查看Request中是否存在"user_token"和Session中是否有"session_token",范围为index.php
    checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );

    // 获取输入值
    $pass_curr = $_GET[ 'password_current' ];   //当前密码
    $pass_new  = $_GET[ 'password_new' ];       //新密码
    $pass_conf = $_GET[ 'password_conf' ];      //确认密码

    // 净化密码输入
    $pass_curr = stripslashes( $pass_curr );    // 从输入中移除反斜杠(转义符)
    // 检查数据库是否连接并对$pass_curr中的值进行转义
    $pass_curr = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"],  $pass_curr ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));
    $pass_curr = md5( $pass_curr ); //使用md5对$pass_curr(旧密码)中的字符串进行加密

    // 验证当前密码是否正确
    // 预处理数据库语句
    $data = $db->prepare( 'SELECT password FROM users WHERE user = (:user) AND password = (:password) LIMIT 1;' );
    $data->bindParam( ':user', dvwaCurrentUser(), PDO::PARAM_STR ); //将:user占位符替换为当前用户
    $data->bindParam( ':password', $pass_curr, PDO::PARAM_STR );    //将:password占位符替换为$pass_curr所对应的md5值
    $data->execute();   // 执行数据库语句

    // 检查新密码和确认密码是否一致,并检查当前用户和旧密码是否匹配
    if( ( $pass_new == $pass_conf ) && ( $data->rowCount() == 1 ) ) {   
        // 如果新密码和确认密码一致,并且查询只有一条数据
        $pass_new = stripslashes( $pass_new );  // 将$pass_new中去除转义字符
        // 查看数据库是连接,并对$pass_new(新密码)中的值进行转义
        $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 );   // 对新密码进行md5加密

        // 更新数据库
        // 预处理sql语句
        $data = $db->prepare( 'UPDATE users SET password = (:password) WHERE user = (:user);' );
        $data->bindParam( ':password', $pass_new, PDO::PARAM_STR ); // 将:password占位符替换为$pass_new(新密码)
        $data->bindParam( ':user', dvwaCurrentUser(), PDO::PARAM_STR ); // 将:user占位符替换为当前用户
        $data->execute();   //执行数据库语句

        // 给用户回显
        echo "<pre>Password Changed.</pre>";
    }
    else {
        // 如果两项中有任意一项不匹配在给用户回显
        echo "<pre>Passwords did not match or current password incorrect.</pre>";
    }
}

// 生成防CSRF令牌
generateSessionToken();

?>

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值