二进制选手的web安全之路(0x2) : CSRF跨站请求伪造
字数 1034 2025-08-10 10:14:26
CSRF跨站请求伪造攻击详解
一、CSRF基本概念
CSRF(Cross-Site Request Forgery,跨站请求伪造)是一种常见的Web安全漏洞。攻击者通过伪造用户的浏览器请求,向用户曾经认证过的网站发送请求,利用受害者尚未失效的身份认证信息(如cookie、会话等),在用户不知情的情况下以用户身份执行非法操作。
CSRF与XSS的区别
- XSS:利用站点对用户输入的信任,注入恶意脚本窃取用户信息
- CSRF:利用站点对用户浏览器的信任,伪造用户请求执行操作
二、DVWA Low级别CSRF漏洞分析
漏洞代码分析
<?php
if( isset( $_GET[ 'Change' ] ) ) {
// 获取输入
$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 );
// 更新数据库
$current_user = dvwaCurrentUser();
$insert = "UPDATE `users` SET password = '$pass_new' WHERE user = '" . $current_user . "'";
$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);
}
?>
漏洞点分析
- 使用GET请求处理敏感操作(密码修改)
- 没有任何CSRF防护措施(如token验证)
- 仅检查密码是否匹配,不验证请求来源
三、CSRF攻击实施步骤
1. 正常操作流程
- 用户登录目标网站
- 访问密码修改页面
- 输入新密码并确认
- 提交表单完成密码修改
2. 攻击者视角
- 构造恶意URL:
http://target-site.com/vulnerabilities/csrf/?Change=1&password_new=123456&password_conf=123456 - 诱骗用户点击该链接(通过邮件、论坛、即时消息等)
- 用户点击时,浏览器会自动携带该网站的cookie发起请求
- 服务器误认为是用户合法操作,执行密码修改
3. 使用Burp Suite生成CSRF PoC
- 拦截正常密码修改请求
- 右键选择"Generate CSRF PoC"
- 在浏览器中测试生成的PoC
四、CSRF防御措施
1. 使用CSRF Token
- 服务器生成随机token并存储在session中
- 每次表单提交必须携带该token
- 服务器验证token有效性
2. 检查Referer头部
- 验证请求来源是否合法
- 但Referer可能被浏览器禁用或伪造
3. 使用SameSite Cookie属性
- 设置Cookie的SameSite属性为Strict或Lax
- 防止跨站请求自动携带Cookie
4. 关键操作使用POST请求
- 避免使用GET请求执行敏感操作
- 虽然POST请求也可能被CSRF攻击,但难度更大
5. 二次验证
- 对于敏感操作(如密码修改、转账等)要求二次验证
- 如短信验证码、邮箱确认等
五、修复后的安全代码示例
<?php
if( isset( $_POST[ 'Change' ] ) ) {
// 验证CSRF Token
if( !isset( $_POST[ 'token' ] ) || $_POST[ 'token' ] != $_SESSION[ 'token' ] ) {
die( 'Invalid CSRF Token' );
}
// 获取输入
$pass_new = $_POST[ 'password_new' ];
$pass_conf = $_POST[ 'password_conf' ];
// 检查密码是否匹配
if( $pass_new == $pass_conf ) {
// 密码匹配
$pass_new = mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $pass_new);
$pass_new = md5( $pass_new );
// 更新数据库
$current_user = dvwaCurrentUser();
$insert = "UPDATE `users` SET password = '$pass_new' WHERE user = '" . $current_user . "'";
$result = mysqli_query($GLOBALS["___mysqli_ston"], $insert ) or die( '<pre>' .
mysqli_error($GLOBALS["___mysqli_ston"]) . '</pre>' );
// 用户反馈
echo "<pre>Password Changed.</pre>";
} else {
// 密码不匹配
echo "<pre>Passwords did not match.</pre>";
}
mysqli_close($GLOBALS["___mysqli_ston"]);
}
?>
六、总结
CSRF攻击利用的是网站对用户浏览器的信任,防御的关键在于让服务器能够区分合法请求和伪造请求。通过结合CSRF Token、SameSite Cookie、请求方法限制等多种措施,可以有效防止CSRF攻击。开发者应特别注意不要使用GET请求执行敏感操作,并对所有可能改变系统状态的操作实施CSRF防护。