安全性测试入门 (三):CSRF 跨站请求伪造攻击和防御
本篇继续对于安全性测试话题,结合DVWA进行研习。
CSRF(Cross-site request forgery):跨站请求伪造

1. 跨站请求伪造攻击
CSRF则通过伪装成受信任用户的请求来利用受信任的网站,诱使用户使用攻击性网站,从而达到直接劫持用户会话的目的。

由于现在的主流浏览器比如火狐和谷歌,都倾向于使用单个进程来管理用户会话(比如我们在FF和Chrome中,当要访问一个新页面时,通常是通过新增浏览器页面来达到的,而不是新开一个浏览器客户端进程),所以攻击者就可以通过用户新开的页面来劫持用户的已有cookie等关键信息。
常见的攻击形式,是通过邮件,QQ等即时聊天工具,给被攻击对象发送伪造链接。被攻击者一旦访问了该恶意链接,攻击即生效。
DVWA的相应模块中,使用一个密码修改功能来展示了CSRF攻击的可能性。

构造攻击
我们观察上述密码修改功能所触发的请求:

可以看到这个请求非常之简单,所需传递的只有三个参数
- password_new
- password_conf
- change
那么如果攻击者直接构造这样一条请求交给被攻击者去执行会怎么样?
比如我构造这样一条URL:

如果被攻击者傻呵呵的点击了,那么恭喜他,他的密码就已经被我改成"attackerpw"了。
当然了,这个链接的攻击意图过于明显了,攻击者还可以通过伪装一下这个链接,从而达到神不知鬼不觉的目的。
- 比如通过缩短链接服务:

- 比如通过构建一个带有攻击代码的页面,诱使被攻击者访问:

上图看起来就是个不明所以的网页?但实际上访问到网页的时候红框部分的攻击代码就已经生效了!
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请求就不应用于处理敏感操作,发现这种情况就是你测试的点!),那么你就可以摩拳擦掌,考虑来一次渗透测试了。
从这个角度来说,对于安全性测试,知识和技术的累积是一方面,而敏锐的思维能力特别是逆向思维能力更加重要!
安全性测试入门 (三):CSRF 跨站请求伪造攻击和防御的更多相关文章
- 教你轻松解决CSRF跨站请求伪造攻击
摘要:CSRF(Cross-site request forgery)跨站请求伪造,通过伪装来自受信任用户的请求来利用受信任的网站.与XSS攻击相比,CSRF攻击往往不大流行(因此对其进行防范的资源也 ...
- SpringSecurity原理解析以及CSRF跨站请求伪造攻击
SpringSecurity SpringSecurity是一个基于Spring开发的非常强大的权限验证框架,其核心功能包括: 认证 (用户登录) 授权 (此用户能够做哪些事情) 攻击防护 (防止伪造 ...
- XSS跨站脚本攻击与CSRF跨站请求伪造攻击的学习总结(转载)
转载自 https://blog.csdn.net/baidu_24024601/article/details/51957270 之前就了解过这方面的知识,但是没有系统地总结.今天在这总结一下,也让 ...
- CSRF(跨站请求伪造攻击)漏洞详解
Cross-Site Request Forgery(CSRF),中文一般译作跨站点 请求伪造.经常入选owasp漏洞列表Top10,在当前web漏洞排行中,与XSS和SQL注入并列前三.与前两者相比 ...
- CSRF(跨站请求伪造)攻击方式
一.CSRF是什么? CSRF(Cross-site request forgery),中文名称:跨站请求伪造,也被称为:one click attack/session riding,缩写为:CSR ...
- 浅谈CSRF(跨站请求伪造)攻击方式
一.CSRF是什么? CSRF(Cross-site request forgery),中文名称:跨站请求伪造,也被称为:one click attack/session riding,缩写为:CSR ...
- DVWA之CSRF(跨站请求伪造攻击)
目录 Low Middle High Impossible Low 源代码: <?php if( isset( $_GET[ 'Change' ] ) ) { // Get input $pas ...
- Django之CSRF跨站请求伪造(老掉牙的钓鱼网站模拟)
首先这是一个测试的代码 请先在setting页面进行下面操作 注释完成后,开始模拟钓鱼网站的跨站请求伪造操作: 前端代码: <!DOCTYPE html> <html lang=&q ...
- 第三百一十五节,Django框架,CSRF跨站请求伪造
第三百一十五节,Django框架,CSRF跨站请求伪造 全局CSRF 如果要启用防止CSRF跨站请求伪造,就需要在中间件开启CSRF #中间件 MIDDLEWARE = [ 'django.midd ...
随机推荐
- android编译遇到问题修改
(注意要确定安装了jdk) 第一步: cd lichee; ./build.sh -p sun5i_elite -k 3.0 (apt-get install uboot-mkimage需要安装 ...
- 对云资源服务商资源读写的架构思考:前端代码走token
第一.统一了访问端接口.提高前端开发速度:第二统一了阿里各个产品的 数据读写模式: 第三,我们的服务器产生token时对读写规则做限制,特定的token由特定的规则产生,而不是让前端代代码去管控限制 ...
- VC实现趋势图绘制
本文参考pudn上一个完整工程,在pudn搜索“50815867CurveDrawing”即可找到源代码. 上图是使用VS2010重写了该软件后的效果图,下面再贴出关键代码: // Plot.cp ...
- MySQL table
-- 使用数据库hr use hr; -- 在数据库中创建表-- ------------------------------------JOBS表-------------------------- ...
- java 获取时间戳
//java 获取时间戳 long currentTime=System.currentTimeMillis();
- css 中的伪类选择器before 与after
.cf:after,.cf:before {content: " "; display: table;} .cf:after {clear: both;} :before是因为ta ...
- 计算一个大数n的阶乘的位数宽度(十进制)(log i累加法 )
输入: 每行输入1个正整数n, (0<n<1000 000) 输出: 对于每个n,输出n!的(十进制)位数. 分析: 这道题采用蛮力法.根据定义,直接求解! 所谓n!的十进制位数,就是 l ...
- Microsoft.XMLHTTP基本用法
客户端调用XMLHTTP的过程很简单,只有5个步骤:1.创建XMLHTTP对象2.打开与服务端的连接,同时定义指令发送方式,服务网页(URL)和请求权限等.客户端通过Open命令打开与服务端的服务网页 ...
- oracle自动统计信息
在11g中,默认自动收集统计信息的时间为晚上10点(周一到周五,4个小时),早上6点(周六,周日,20个小时), select a.window_name, a.repeat_interval,a ...
- 「咕咕网校 - 基础省选」树上问题的进阶 by Drench
一定要在noip之前把自己花钱买的Luogu网课梳理完!QAQ 树上前缀和: 对于有根树,在每个点记录 val (点权) 和 sum(到根的点权之和) 当然记录的值因题而异(但是既然叫树上前缀和当然就 ...