Web安全:CSRF跨站请求伪造攻击解析

CSRF漏洞简介

1. CSRF漏洞简介
跨站请求伪造(Cross-site request forgery),通常缩写为CSRF, 是一种挟制用户在当前已登录的Web应用程序上执行非本意的操作的攻击方法。OWASP于2007年将CSRF归类进 OWASP TOP10 的安全风险中。

2. CSRF漏洞原理
CSRF是攻击者可伪造当前用户的行为,让目标服务器误以为请求由当前用户发起,并利用当前用户权限实现业务请求伪造。
CSRF侧重于伪造特定用户的请求。
在这里插入图片描述
3. CSRF漏洞关键点

  • 用户维持目标网站登陆状态:目标站点会话失效时间比较长,且失效时间越长受攻击纪律越高。
  • 后台未对业务开展合法性校验:对特殊敏感操作没有严谨的用户身份验证。
  • 跨站点的请求:跨站点请求的来源是其他站点,比如:删除文章功能收到来自恶意站点发出的删除文章请求,这个请求就是跨站点的请求,但恶意请求也可能来自本站。
  • 请求是伪造的:如果发出的请求不是用户的意愿,那可以认为这个请求就是伪造的,即用户主动访问含有伪造请求的页面。

4. CSRF漏洞演示
DVWA平台Low难度为例:
页面存在修改密码功能,当已登陆用户输入新密码并提交时,才会修改为新密码。
在这里插入图片描述
New password的名称为password_newConfirm new password的名称为password_conf
页面源码:

<?php

if( isset( $_GET[ 'Change' ] ) ) {
    // 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
        echo "<pre>Password Changed.</pre>";
    }
    else {
        // Issue with passwords matching
        echo "<pre>Passwords did not match.</pre>";
    }

    ((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);
}

?>

服务器接收请求后只对传入的两次密码做了比较,相同则执行修改密码操作。没有任何CSRF防范机制,可以构造GET传参:

http://.../csrf/?password_new=hack&password_conf=hack&Change=Change#

欺骗用户访问并得到返回的页面,已经将当前用户密码修改为hack在这里插入图片描述
但这只是最基础的CSRF攻击,用户可以很明显通过链接或返回页面判断出网站存在不安全因素。我们可以对链接进行隐藏,例如:

隐藏在HTML标签中,在恶意网站编写跳转链接,欺骗用户访问

...
<img src="http://.../csrf/?password_new=hack&password_conf=hack&Change=Change#" border="0" style="display:none;"/>
...

因为Web层面存在同源策略,限制了客户端脚本的跨域请求行为。但实际上由客户端HTML标签中发出的跨域GET请求被认为是合法的,但是这些请求发出后并不允许得到目标页面响应的数据内容。
将攻击代码隐藏在正常的流程中,用户无需对链接进行点击,在访问包含存在攻击代码的<img><iframe><script>等标签中,客户端发出了修改密码的GET请求,由于是合法的跨域请求,浏览器会执行该语句但不会返回响应数据。
由此完成了一次伪装后的CSRF攻击

在这次CSRF攻击过程中,存在三个关键点:

  • 跨域发出请求:由于同源策略限制了客户端脚本的跨域请求行为,所以通过客户端访问恶意页面后由HTML标签发出跨域的GET请求,以此完成攻击。
  • 可以无JavaScript参与:与XSS攻击不同,有无JavaScript的参与都可完成攻击,也可以通过动态生成一个img对象达到同样的攻击效果。
<script>
new Image().src = "http://.../csrf/?password_new=hack&password_conf=hack&Change=Change#"
</script>

通过JavaScript间接生成一个img对象,由img对象发起一个合法的跨域GET请求,与之前直接使用<img>标签一样。

  • 已存在目标网站身份认证
    在原网页修改密码部分请求头信息:
...
Cookie: PHPSESSID=2b4lmlsjhnfcnj9rpda505evs6; security=low
Referer: http://.../csrf/
...

通过构造的攻击链接访问的部分请求头:

...
Cookie: PHPSESSID=2b4lmlsjhnfcnj9rpda505evs6; security=low
...

二者对比可得知,构造的攻击链接相比与原网站访问,缺失了Referer属性的值,或是恶意网站的地址。其中的Cookie是用户登陆目标网站后的身份认证标志。跨域发出的请求也会带上目标网站用户的Cookie值,这样的请求只能存在与用户身份认证后,攻击才能成功。

:只演示了基础的GET传参方式,POST方式也是相同的原理,在一个跨域伪造的POST表单请求发出时,这个请求也可以携带目标网站用户的Cookie

Cookie分为本地Cookie内存Cookie,这两类在CSRF的过程中会存在一些差异,IE浏览器默认不允许恶意网站的本地Cookie在这样的跨域请求中携带,除非在HTTP响应头设置了P3P(Platform for Privacy Preferences),这个响应头告诉浏览器允许网站跨域请求目标网站时带上目标网站的用户本地Cookie,对于非IE浏览器,没有这样的限制。

CSRF攻击类型

按请求类型

分为GET型与POST型。

按攻击方式

1. HTML CSRF攻击
CSRF请求是由HTML元素发出的,是最普遍的CSRF攻击,在HTML中能够设置srchref属性的标签都可以发出一个GET请求,例如:

<link href="xxx">
<img src="xxx">
<ifarame src="xxx">
<bgsound src="xxx">
<a href="xxx">
...

在CSS样式中:

@import " "
background:url("xxx")
...

通过JavaScript动态生成的标签对象或CSS对象发起的POST的请求,请求通过form方式提交。

2. 转换为短链接
由于原链接较为直观的可以发现存在不安全因素,由此可以转换为短链接,将原链接与参数隐藏:
在这里插入图片描述
访问短网址一样会得到与访问原链接一样的结果,虽然隐藏了原地址与参数,但还是会返回结果页面,也不算是一种高明的手法。所以在真实环境中将短链接与伪装页面相结合,达到更真实的效果。

3. JSON HiJacking攻击
JSON HiJacking技术非常经典,攻击过程是CSRF,不过是对AJAX响应中最常见的JSON数据类型进行的劫持攻击。很多时候,网站发出的AJAX请求,响应的数据是JSON格式:

  • 字典格式
{
	"password_new": "hack",
	"password_conf": "hack",
	"Change": "Change",
}
  • 列表格式
['hack', 'hack', '...']

每个键值可以是数字、字符串、布尔值、字典、列表、null等,最终呈现出来的是一份结构清晰且完整的字典结构或列表结构。由于JSON格式的简介与强大,网站开发逐渐使用JSON代替传统的XML进行数据传输。JSON在各种语言中都到了完美的支持,这里以JavaScript为例:

JSON数据如果以字典形式返回,直接在显示器中会显示报错,原因是浏览器以为“{”开头的脚本应该是一段左右花括号包围住的代码块,所以,对于这种JSON数据的处理,一般会这样:

eval("("+JSON_DATA+")");	// 将数据前后加上圆括号

对于使用列表形式返回的JSON数据,将会是一个Array对象,以前可以通过劫持Array数据进行JSON HiJacking攻击,但是现在已经不行了。

以前的饭否JSON HiJacking案例可做参考。

4. Flash CSRF攻击
Flash同样遵循同源策略,发起的CSRF攻击是通过ActionScript脚本完成的,通常包含以下两个关键点:

  • 跨域获取隐私数据
    如果目标网站根目录下存在crossdomain.xml文件,配置如下:
<?xml version="1.0" ?>
<cross-domain-policy>
<allow-access-from domain="*" />
</cross-domain-policy>

配置中的<allow-access-from domain="*" />表示允许任何域的Flash请求本域的资源。这样就很危险,如果用户已登陆目标网站,被欺骗访问包含恶意Flash的网页时,自己的隐私数据可能也被盗走。

这个恶意的Flash的ActionScript脚本如下:

import flash.net.*;
// 请求隐私数据所在的页面
var loader = new URLLoader(new URLRequest("http://www.foo.com,private"));
loader.addEventLostener(Event.COMPLETE,function(){   // 当请求完成后
loader.data;	// 获取到的隐私数据
// 更多操作
});
loader.load();	// 发起请求
  • 跨域提交数据操作:增删改查等操作的请求,并不会获取到隐私数据。
    这个就不需要crossdomain.xml的跨域访问策略了,由于跨域发起的GET/POST请求对于浏览器来说就是合法的,那么在Flash里进行也一样。

CSRF漏洞利用场景

经过前期对CSRF漏洞的分析可知,这类漏洞在利用方面的条件比较苛刻,因为必须在用户已登陆的状态下触发目标链接。也正是由于这个特点,在开发时很容易户数CSRF攻击带来的危害。在真实场景下,如果CSRF被利用,很可能会带来巨大的安全隐患。比如:

1. 管理员权限执行
当用户是管理员身份并存在CSRF漏洞时,攻击者可根据业务功能特点构造语句,在管理员不知情的情况下发起业务请求,篡改目标网站上的 用户数据,对业务造成严重影响。

2. 个人用户权限
作为其他攻击向量的辅助攻击手法,如果CSRF漏洞配合存储型XSS漏洞,可实现在当前用户页面上嵌入攻击伪造链接,从而大大增加用户点击的可能性,形成触发攻击的隐患。若社交网站上存在此问题,则会产生类似蠕虫的攻击效果。

3. 伪装身份
以当前用户的身份发送邮件、消息等行为实施诈骗或套取信息。盗取账户信息后购买商品、虚拟货币等行为,引发财产安全问题。

4. 管理系统
考虑到用户使用系统的便利性,可以在后台Web页面上开发特定功能来实现针对管理系统的参数调整。每次在针对管理系统进行参数调整时,都会想服务器发送一次请求。因此,如果CSRF伪造管理员的高危功能请求并诱导管理员执行,那么会对当前系统造成非常大的危害。

针对CSRF防护方案

CSRF一般是由于Web系统对当前用户身份的验证不足而造成的,比如目标站点并未对提交的请求做合法校验,导致任意请求均可执行(在用户合法登陆的前提下,业务流程正常的请求)。尽管攻击方式千变万化,但归根结底都是没有充分验证当前业务的合法性而造成的。因此常用的防护手段重点在于为关键业务点添加合理的验证方式,以实现对用户合法身份的二次确认。

添加中间环节

由于攻击者只能仿冒用户发起请求,并不能接受服务器的响应内容,因此可在请求被执行前添加防护措施。主要思路为在发起关键业务的请求时,多添加一步验证环节,并保证环节的内容无法被攻击者获取或碰撞,从而有效避免攻击者伪造请求的情况。

这个过程中,常用的方式有以下两种:

1. 添加验证过程
CSRF漏洞可成功利用的一个显著特点是攻击者伪造的用户请求会被服务器实际执行。对此,最有效的手段就是在其中添加一个中间过程,如让用户进行确认,从而可以避免这类问题出现。
当用户填写完表单内容点击submit后,服务器会接收到内容,并弹出一个确认框,让用户进行二次确认。在这种环境下,由于攻击者无法接收到服务器的确认内容,也就无法进行确认提交的业务流程,CSRF漏洞利用失败。

注:在添加验证过程时需要注意,确认流程应由页面接受后在前端显示,不要利用纯前端的技术来实现,如利用JavaScript代码来实现上述确认功能,否则就会失去二次验证的意义。

2. 添加验证码
在业务角度针对CSRF防护的另一种有效的方式是添加验证码机制。在用户提交内容时需要输入验证码,利用验证码来确认是否是当前用户发起的请求。验证码对CSRF攻击防护效果良好,但是验证码最好是在关键业务流程点使用。如果在业务流程中过多使用验证码,会导致用户体验严重下降。

:同时,验证码也存在一定安全隐患,但是攻击者无法利用验证码的安全隐患成功实现对CSRF漏洞的利用。

3. 双提交Cookie
对于Ajax请求来说,可以使用双提交Cookie的方式。简单来说,就是在提交关键请求时,先用JavaScript代码读取用于验证Cookie值加入到提交字段中。这样就形成了双提交。显然单纯的CSRF只能让请求中带有Cookie,但是并不能读取Cookie并加入到请求提交字段中。

验证用户请求合法性

防护CSRF漏洞的另一个方面是需要对每次请求的合法性进行校验。保证当前请求是由用户本人发起。这是解决CSRF的成因——伪造用户请求的最直接的方式。

验证用户合法性可从以下两个方面着手:

1. 验证Referer
由于CSRF请求发起方为攻击者,因此在Referer属性处,攻击者与当前用户所处的界面是完全不同的。可用过验证Referer值是否合法,即通过验证请求来源的方式确定此次请求是否正常。

...
Cookie: PHPSESSID=2b4lmlsjhnfcnj9rpda505evs6; security=low
Referer: http://.../csrf/
...

但是, 在某些情况下Referer验证也存在一定缺陷,即可以利用伪造的方式实现对Referer验证的绕过。

推荐利用Referer来监控CSRF行为,如果将其用于防御,效果不是很好。

2. 利用token
针对CSRF漏洞,在开发Web系统时一般会利用token来识别当前用户身份的真实性。token在当前用户第一次访问某项功能页面时生成,且token是一次性的,在生成完毕后有服务器发给客户端。用户端接收到token之后,会在进行下一步业务时提交token,并由服务器进行有效验证。

由于攻击者在CSRF利用时无法获得当前用户的token,导致就算链接发送成功,也会由于没有携带有效token值,导致针对请求的验证发送错误。

生成token的方式非常灵活,可通过当前用户名+随机数、随机数的MD5值等多种方式生成。根据当前用户提交的情况进行token验证及更新。在每次访问之后都会进行token值的更新。

在使用token时需要遵守以下原则:

  • 必须为一次性,无论业务流程成功或失败,在每次用户请求时均重新生成token并在客户端进行更新。
  • 较强的随机性,避免采取简单的可预测方式,使攻击者猜测出生成规律,导致token失效。

用户层面

尽管CSRF是Web应用层面的漏洞,但用户可以通过一些操作保护自身账户安全。比如登陆缺乏安全设计的网站时,在浏览其他站点前退出已登陆站点活在浏览器会话结束后清理浏览器的Cookie数据在这里插入图片描述

CSRF漏洞的检测

检测CSRF漏洞是一项比较繁琐的工作,针对防护方案可以有以下几个方式:

  • 抓取一个正常请求的数据包,去掉Referer字段后再次提交,查看提交是否有效
  • 关键业务处的用户身份验证,验证码、token等方式
  • 针对CSRF漏洞进行检测的工具:CSRF Tester、CSRF Request Builder

CSRF 漏洞总结

CSRF漏洞的利用条件较为苛刻,但如果被利用依然会带来非常严重的危害。与其他Web漏洞不同的是,CSRF的防护不会关注对连接、提交参数的过滤,而是重点对业务开展的合法性进行验证,如验证请求是否来自与当前用户、在重点功能处添加验证环节、通过token进行验证等。

总体来说,CSRF防护的手段较为简单,同时清晰有效,可以根据业务实际需要选择适当的防护方式。

参考资料

1. 《Web安全防护指南》基础篇——蔡晶晶 张兆心 林天翔
2. 《Web 前端黑客技术揭秘》——钟晨鸣
3. 「网络安全涨姿势」第11期——浦东网警巡查执法

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值