CSRF与SSRF

本文最后更新于:2023年4月13日 晚上

何为CSRF

CSRF (Cross-Site Request Forgery) 即跨站请求伪造,CSRF利用的是对用户浏览器的信任,如果用户登陆了一个网站浏览器就会保存用户的cookie,以后对该域的的每一个请求都会携带用户凭证(cookie),这时攻击者发送了某个操作的链接给用户,用户点击之后,就会携带自己的cookie发起请求,完成相应的操作。

CSRF的分类[1]

GET类型

对应的csrf是通过get请求产生的,例如通过img标签:

1
<img src="https://csrf.xxx.com/admin.php?xx=xx&aa=aa" />

当用户访问包含csrf链接的图片的页面时,就会产生get型csrf。

POST类型

对应的csrf是通过post请求产生的,通常是利用表单提交:

1
2
3
4
<form action="https://csrf.xxx.com/admin.php" method=POST>
<input type="text" name="xx" value="xx">
</form>
<script> document.forms[0].submit();</script>

当用户访问包含csrf的表单的页面时,就会产生post型csrf。

链接类型

对应的csrf是通过点击链接产生的,通常是利用a标签:

1
<a href="https://csrf.xxx.com/admin.php?xx=xx&aa=aa" target="_blank">是兄弟就来砍我!</a>

当用户点击链接想去砍兄弟时,就会产生链接型csrf。

其他类型

过基础认证的csrf,通常用于路由器:

1
<img src="http://admin:admin@192.168.1.1" />

加载图片后,路由器会给用户一个合法的session。

CSRF的防御

验证 Referer

referer 记录了http请求的来源地址,因为csrf攻击一般都是通过跨域发起的请求,所有验证referer是否来自本域或者上一级页面能够有效防止部分csrf,但因为referer是依赖第三方来保障的(例如浏览器),所以此方法并不算安全。

token

从csrf的实现原理来看,是因为攻击者能够构造用户的请求,所以可以在http请求里以参数的形式加入一个随机的token,并在服务器建立一个拦截器验证这个token,相对于referer,token要更加安全一些。但是token的安全也是难以保证万无一失的,在一些支持用户自己发表内容的网站上,如果攻击者把个人网站发布在上面,当用户点击之后也可能携带自己的token去访问,这样攻击者就可以得到这个token。如果在添加token功能处添加判断,当通向他域的时候不添加token,攻击者也可以通过referer拿到这个token值。所以添加token的方法也并不完美。

http头自定义属性

这种形式是通过把token放置到http头自定义属性里,通过XMLHttpRequest这个类,可以一次性给所有该类请求加上csrftoken这个HTTP头属性,并把token值放入其中。这样解决了上种方法在请求中加入token的不便,同时,通过XMLHttpRequest请求的地址不会被记录到浏览器的地址栏,也不用担心token会透过Referer泄露到其他网站中去。然而这种方法的局限性非常大。XMLHttpRequest请求通常用于Ajax方法中对于页面局部的异步刷新,并非所有的请求都适合用这个类来发起,而且通过该类请求得到的页面不能被浏览器所记录下,从而进行前进,后退,刷新,收藏等操作,给用户带来不便。另外,对于没有进行CSRF防护的遗留系统来说,要采用这种方法来进行防护,要把所有请求都改为XMLHttpRequest请求,这样几乎是要重写整个网站,这代价无疑是不能接受的。

使用严格的 SameSite

Cookie 有一个 SameSite 属性,设置为严格模式(非 none 值),可以让其他网站的中跨域请求不带上 Cookie。

人机校验

加一个短信校验、邮箱校验、验证码什么的,确保是一个人在尝试发这个请求。缺点是用户体验不太好。

双重Cookie验证

利用CSRF攻击不能获取到用户Cookie的特点,我们可以要求Ajax和表单请求携带一个Cookie中的值。后端接口验证Cookie中的字段与URL参数中的字段是否一致,不一致则拒绝。
优点是可以直接通过前后端拦截的的方法自动化实现。后端校验也更加方便,只需进行请求中字段的对比,而不需要再进行查询和存储Token。
缺点是任何跨域都会导致前端无法获取Cookie中的字段(包括子域名之间),而且如果有其他漏洞(例如XSS),攻击者可以注入Cookie,那么该防御方式失效。

何为SSRF

SSRF (Server-Side Request Forgery) 即服务端请求伪造,SSRF利用的是对服务器的信任,服务器使用用户输入的URL进行资源请求时,未对该URL进行安全校验,通过伪造一个服务端请求发起攻击,攻击者借由服务端为跳板来攻击目标系统。

SSRF 发生的地点

  1. 社交分享功能:获取超链接的标题等内容进行显示
  2. 转码服务:通过URL地址把原地址的网页内容调优使其适合手机屏幕浏览
  3. 在线翻译:给网址翻译对应网页的内容
  4. 图片加载/下载:例如富文本编辑器中的点击下载图片到本地;通过URL地址加载或下载图片
  5. 图片/文章收藏功能:主要网站会取URL地址中title以及文本的内容作为显示以求一个好的用户体验
  6. 云服务厂商:它会远程执行一些命令来判断网站是否存活等,所以如果可以捕获相应的信息,就可以进行SSRF测试
  7. 网站采集,网站抓取的地方:一些网站会针对你输入的url进行一些信息采集工作
  8. 数据库内置功能:数据库的比如mongodb的copyDatabase函数
  9. 邮件系统:比如接收邮件服务器地址
  10. 编码处理, 属性信息处理,文件处理:比如ffpmg,ImageMagick,docx,pdf,xml处理器等
  11. 未公开的api实现以及其他扩展调用URL的功能:可以利用google 语法加上这些关键字去寻找SSRF漏洞,一些的url中的关键字:share、wap、url、link、src、source、target、u、3g、display、sourceURl、imageURL、domain……
  12. 从远程服务器请求资源(upload from url 如discuz!;import & expost rss feed 如web blog;使用了xml引擎对象的地方 如wordpress xmlrpc.php)

SSRF 危险函数

1
2
3
4
file_get_contents() //把 **传入的参数(变量)**写入字符串,传参是内网文件的时候,会先去吧这个文件的内容读出来再写入
fsockopen($hostname,$port,$errno,$errstr,$timeout) //打开一个网络连接或者一个Unix套接字连接,返回一个文件句柄,fgets(),fgetss(),fwrite(),fclose()还有feof()调用
curl_exec() //函数初始化一个新的会话,返回一个 cURL 句柄,curl_setopt(),curl_exec()和curl_close()调用,可使用伪协议
soapClient()

SSRF 伪协议

  1. file协议: 只能读取当前被攻击机的文件,内网机器文件不能读取
  2. dict协议:泄露安装软件版本信息,查看端口,操作内网redis服务等
  3. gopher协议:gopher支持发出GET、POST请求。可以先截获get请求包和post请求包,再构造成符合gopher协议的请求。gopher协议是ssrf利用中一个最强大的协议(俗称万能协议)。可用于反弹shell
  4. SFTP协议
  5. TFTP协议
  6. LDAP协议

SSRF的防御与绕过

防御:

  • 限制域名: 匹配允许访问的网址
  • 限制协议: 仅允许http和https请求。
  • 限制IP: 避免应用被用来获取内网数据,攻击内网。
  • 限制端口: 限制请求的端口为http常用的端口,比如,80,443,8080,8090。
  • 过滤返回信息: 验证远程服务器对请求的响应是比较简单的方法。
  • 统一错误信息: 免用户可以根据错误信息来判断远端服务器的端口状态

绕过:

  • 使用@绕过

    1
    http//baidu.com@1.1.1.1  // 与http://1.1.1.1效果是一样的
  • 进制转换

    1
    2
    3
    4
    5
    6
    7
    8
    字符串:       10.0.0.3
    二进制: 00001010 . 00000000 . 00000000 . 00000011
    十六进制: 0A.00.00.03
    整数: 167772163
    // 8进制代替10进制,在计算机的世界里,一旦在20前面加个0就会变成8进制
    十六进制: http://0x0A.0x00.0x00.0x03
    八进制: http://012.00.00.03
    八进制溢出: http://265.0.0.3
  • 使用代替.

    1
    http://1270.0.1   // http://127.0.0.1
  • 泛域名解析
    使用xip.io(37signals开发实现的定制DNS服务) 和 xip.name 绕过:

    1
    2
    3
    4
    10.0.0.1.xip.io # 解析到 10.0.0.1
    www.10.0.0.2.xip.io # www 子域解析到 10.0.0.2
    mysite.10.0.0.3.xip.io # mysite 子域解析到 10.0.0.3
    foo.bar.10.0.0.4.xip.io # foo.bar 子域解析到 10.0.0.4
  • 127.0.0.1 绕过

    1
    2
    3
    http://localhost:80
    http://[::]:80
    http://0/
  • Enclosed alphanumerics

    1
    http://ⓔⓧⓐⓜⓟⓛⓔ.ⓒⓞⓜ  // http://example.com
  • 使用302跳转

  • DNS重绑

参考


CSRF与SSRF
https://shenysec.github.io/2023/04/03/CSRF与SSRF/
作者
sheny
发布于
2023年4月3日
更新于
2023年4月13日
许可协议