自己一直分不太清这两者之间的区别,写一篇博文加强下。
一.什么是CSRF和SSRF
1.1 CSRF(Cross Site Request Forggery)
1.1.1 介绍
中文简称:跨站请求伪造,重点主要是在跨站以及伪造两个上。攻击者盗用你的身份,以你的名义发送恶意请求。CSRF是跨站请求伪造,不攻击网站服务器,而是冒充用户在站内的正常操作。
存在原因:通常是由于服务端没有对请求头做严格过滤引起的。
后果:CSRF会造成密码重置,用户伪造等问题,可能会引发严重后果。
1.1.2 利用条件
- www.XXX.com这个网站在用户修改个人信息时没有进行过多的校验,导致这个请求容易被伪造。
- 因此,我们判断一个网站是否存在CSRF漏洞,其实就是判断其对关键信息(如密码,账户号码等敏感信息)的操作(增删改)是否容易被伪造。
- 被攻击者点击了攻击者发送的恶意链接
- 被攻击者正好登录在www.XXX.com这个网站上
1.1.3 CSRF与XSS
- XSS:如果小黑事先在xx网的首页如果发现了一个XSS漏洞,则小黑可能会这样做:欺骗小绿访问埋伏了XSS脚本(盗取cookie的脚本)的页面,小绿中招,小黑拿到小绿的cookie,然后小黑顺利登录到小绿的后台,小黑自己修改小绿的相关信息。
- 对比一下,可以看出CSRF与XSS的区别:CSRF是借用户的权限完成攻击,攻击者并没有拿到用户的权限,而XSS是直接盗取到了用户的权限,然后实施破坏。
- CSRF与XSS最大的区别就在于,CSRF并没有盗取cookie而是直接利用。在2017年发布的新版OWASP Top10中,CSRF排名第8。
1.2 SSRF
1.2.1 成因
SSRF形成的原因大都是由于服务端提供了从其他服务器应用获取数据的功能,且没有对目标地址做过滤与限制。比如从指定URL地址获取网页文本内容,加载指定地址的图片,文档,等等。
SSRF的诞生就是因为攻击者无法直接访问到要攻击的目标主机或服务器,因此用可访问的服务器作为跳板间接去攻击。
1.2.2 原理
首先,我们要对目标网站的架构了解,脑子里要有一个架构图。比如:A网站,是一个所有人都可以访问的外网网站,B网站是一个他们内部的OA网站,我们普通用户只可以访问a网站,不能访问b网站。但是我们可以通过a网站做中间人:访问b网站,从而达到攻击b网站需求。
正常用户访问网站的流程是:
输入A网站URL->发送请求->A服务器接受请求(没有过滤),并处理-->返回用户响应
[那网站有个请求是www.1234.com/xxx.php?image=URL]
那么产生SSRF漏洞的环节在哪里呢?
安全的网站应接收请求后,会检测请求的合法性
产生的原因:服务器端的验证并没有对其请求获取图片的参数(image=)做出严格的过滤以及限制,导致A网站可以从其他服务器的获取数据。
所以,这里就大概类比下CSRF和SSRF之间的区别:
- SSRF是攻击方拿到服务器的一个身份,然后利用服务器以此作为跳板去攻击它的内网或者其他服务器的
- 而CSRF是攻击者拿到用户的身份信息去攻击服务器
1.2.3 利用
- 可以对外网、服务器所在内网、本地进行端口扫描,获取一些服务的banner信息;
- 攻击运行在内网或本地的应用程序(比如溢出);
- 对内网web应用进行指纹识别,通过访问默认文件实现;
- 攻击内外网的web应用,主要是使用get参数就可以实现的攻击(比如struts:2,sgli等);
- 利用file协议读取本地文件等;
常见位置:从一点可以分辨,就是URL中的参数部分是一个链接。下面分享的几种方式,大家可以思考下为什么以及出现问题的地方在哪里。
- 通过URL地址分享网页内容
- 转码服务
- 在线翻译
- 图片加载与下载:通过URL地址加载或下载图片
- 图片、文章收藏功能
- 未公开的api实现以及其他调用URL的功能
- 从URL关键字中寻找share、wap、url、src...
/**所有通过调取外部资源的参数都有可能存在SSRF***/
1.2.4 SSRF防护绕过
利用解析URL出现的问题:
在某些情况下,后端程序可能会对访问的URL进行解析,对解析出来的host地址进行过滤。这时候可能会出现对URL参数解析不当,导致可以绕过过滤。
下面是利用URL特性进行跳转的方式:
以用户名“user”和密码“pwd”访问:http://123.com:pwd@192.168.0.1/
以用户名“user”访问:http://123.com@192.168.0.1/
利用这种方式,就可以使用http://123.com绕过一些URL检测的正则,但实际访问的是内网IP:192.168.0.1
file_get_contents:
SSRF漏洞就是通过篡改获取资源的请求发送给服务器,但是服务器并没有检测这个请求是否合法的,然后服务器以他的身份来访问其他服务器的ssrf攻击可能存在任何语言编写的应用,我们通过一些php实现的代码来作为样例分析。代码的大部分来自于真实的应用源码。
<?php
if (isset($_POST['url'])) // 更正变量名为'url',假设您想通过POST传递一个URL
{
$content = file_get_contents($_POST['url']); // 获取URL内容
$filename = './images/' . rand() . 'img1.jpg'; // 生成随机文件名,注意rand()函数的用法,您原代码中多了一个括号
file_put_contents($filename, $content); // 将内容保存到本地文件
echo $_POST['url'] . "<br>"; // 输出原始URL,并添加换行以便于阅读
// 注意:在实际应用中直接输出用户提供的URL或文件内容可能存在安全风险,确保进行了充分的验证和过滤
$img = "<img src=\"" . htmlspecialchars($filename, ENT_QUOTES, 'UTF-8') . "\" alt=\"Image\">"; // 使用htmlspecialchars防止XSS攻击,同时添加alt属性
}
echo $img; // 输出图片标签
?>
二.DVWA实战靶场演练
2.1 CSRF
2.1.1 LOW
攻击步骤:
- 抓包修改数据包
- 将修改过的数据包做成一个连接,哄骗用户点击重新发送即
注意:
现实攻击场景下,这种方法需要事先在公网上传一个攻击页面诱骗受害者去访问,真正能够在受害者不知情的情况下完成CSRF攻击。这里的演示就是在本地写一个test.html。
首先提交密码修改请求
可以看到提交修改的链接变成如下:
主要要注意的就是后面这个部分,这就是提交到服务器的参数,将密码修改为123456:
/?password_new=123456&password_conf=123456&Change=Change#
然后抓包,查看数据是已经修改成功了:
知道修改密码的机制之后,接下来就好办了,我们可以构造一条链接,然后进行伪装发送给受害者点击:
这里就写一个简单的HTML页面
<html>
恭喜你中奖了,前往领奖
<a href="https://3mw.cn/08b21">点击领奖</a>
</html>
然后直接跳转,显示密码已修改:
接下来测试一下,看看结果,是已经修改成功了:
2.1.2 Medium
这一个难度是加入了referer验证,抓包看下,请求头里面是有添加一个referer的标头,对源码分析也发现了来源请求校验:
这种的一般是通过修改referer证据链,可以参考这篇文章:CSRF--花式绕过Referer技巧 - 知乎 (zhihu.com)
其实大家在这里可以关注一个问题:添加了referer之后,怎么就可以进行防护了呢,对什么字段或内容进行校验的呢
2.1.3 High
- 加入token
- High级别的代码加入了Anti-CSRF token机制,用户每次访问改密页面时,服务器会返回一个随机的token,向服务器发起请求时,需要提交token参数,而服务器在收到请求时,会优先检查token,只有token正确,才会处理客户端的请求。对于user_token,而且每次修改密码,它都是变化的。因此,使用low和Medium的方法无效
- 绕过方式利用XSS绕过
- 用xss脚本获得用户的token
<iframe src="../csrf" onload="alert(frames[0].document.getElementsByName('user_token')[0].value) />
- 用token进行修改密码操作
代码解析:
JSON格式的POST请求处理
条件判断:首先检查几个条件来确定是否为JSON格式的POST请求。
$_SERVER['REQUEST_METHOD'] == "POST"
确保请求是POST类型。array_key_exists("CONTENT_TYPE", $_SERVER)
检查是否存在CONTENT_TYPE
头部。$_SERVER['CONTENT_TYPE'] == "application/json"
确认内容类型为JSON。读取并解析JSON数据:如果上述条件满足,使用
file_get_contents('php://input')
读取请求的原始输入数据(即JSON字符串),然后通过json_decode
将其转换为PHP数组(第二个参数true
表示需要转换成关联数组而非对象)。设置请求类型标记:设置
$request_type = "json"
,这一步虽然在这个片段中没有直接使用,但可能用于后续逻辑区分请求来源。验证请求内容:进一步检查是否包含必要的字段,包括HTTP头部中的
HTTP_USER_TOKEN
以及解码后的JSON数据中的password_new
、password_conf
和Change
。如果这些都存在,它将相关值赋给变量,并设置$change = true
,表明可以继续执行密码变更的逻辑(这部分逻辑未在代码中展示)。普通表单POST请求处理
- 如果前面的JSON请求条件不满足(即不是JSON格式的POST请求),则进入
else
部分,这里检查是否为普通表单提交的POST请求。- 使用
$_REQUEST
全局数组来检查是否存在user_token
、password_new
、password_conf
和Change
这些表单字段。如果这些字段都存在,同样地,将它们的值分别赋给对应变量,并设置$change = true
。总结
这段代码根据请求的内容类型(JSON或表单数据)灵活处理密码变更的请求,提取出必要的参数(用户令牌、新密码、确认密码,以及一个疑似触发变更操作的标志)。这是一种常见的处理API请求和传统表单提交的实践,确保了服务端能兼容不同客户端的请求格式。需要注意的是,实际应用中还需添加相应的错误处理逻辑和密码变更的具体实现。
然后是用XSS来获取token:
2.2 SSRF
三.如何进行防护
3.1 CSRF
- 对敏感信息的操作增加安全的token;
- 对敏感信息的操作增加安全的验证码;
- 对敏感信息的操作实施安全的逻辑流程,比如修改密码时,需要先校验旧密码等。