CSRF攻击原理解析二
Author: rayh4c [80sec]
EMail: rayh4c#80sec.com
Site: http://www.80sec.com
Date: 2008-12-31
From: http://www.80sec.com/release/csrf-securit2.txt
0×00 说明提醒
由于CSRF攻击原理解析老版本文档中的部分内容不是很严谨,一定程度上误导了大家,这里我表示歉意。这个文档将重新从浏览器安全和cookie原理的角度对CSRF漏洞进行分析,理顺CSRF的攻击原理,修正老版本文档中的部分错误概念和思路,同时希望这次的修正可以帮助大家更深层次的研究Web安全问题。
0×01 本地cookie和内存cookie的误区
在老文档中我提出了本地COOIKIE和内存cookie两个概念,这两个概念是相对于系统和浏览器来说明的。本地cookie是浏览器保存在系统中的数据,在设置了cookie的expires参数的值也就是指定了cookie的失效时间的情况下,IE等浏览器会将cookie以文本格式保存在浏览器的临时目录里。内存cookie是当前浏览器进程保存的数据,在没有设置cookie的expires参数值的情况下,当浏览器进程结束时内存cookie也就消失了。具体参考如下cookie的标准格式:
Set-Cookie: <name>=<value>[; <name>=<value>] [; expires=<date>][; domain=<domain_name>] [; path=<some_path>][; secure][; HttpOnly]
在这里本地cookie和内存cookie的概念存在一个误区,误区存在于我们对于cookie与Web程序身份认证及会话的理解,首先我们必须明晰Session的概念,Session是由服务器维持的一个服务器端的存储空间,用户在连接服务器时,会由服务器生成一个唯一的SessionID,用该SessionID为标识符来存取服务器端的Session存储空间。SessionID可以由cookie保存,用户访问网站时,SessionID将会随cookie提交到服务器端。服务器也可以通过URL重写的方式来传递SessionID的值,但是在URL中传递SessionID是存在很大的安全风险的,黑客可能获取HTTP请求的来源信息等手段直接就得到了客户端的SessionID。
其次我们应该认识到cookie和session的区别,因为这里的概念是混淆和模糊的。HTTP协议是无状态的,客户端与服务端无法长期的保存身份认证及会话状态,所以便需要cookie机制,在客户端以文件的形式保存会话状态。而session机制则是在服务器端保持状态,不需要长期保持会话状态,但是服务器端保持状态的同时在客户端也需要保存一个标识,前面我提到了使用URL传递SessionID的安全风险,所以session机制需要借助于cookie机制。原理上cookie只是做为SessionID的一个载体,我们只需要区分cookie机制和session机制即可。
最后我对老文档中关于本地cookie和内存cookie的概念做一次修正,参照上面的分析和Web标准,这两种cookie严谨的说,应该称为会话cookie和持久化cookie。下面的0×02、0×03部分我将对老文档中的浏览器的安全缺陷内容做第二次的修正。
0×02 浅析cookie的同源策略
同源策略是今年被提起比较多的一个安全概念,这个策略是浏览器的安全基础,cookie做为浏览器的一个功能,自然也考虑到了同源策略,cookie的同源策略分为两个方面,第一个方面涉及到cookie的domain和path两个值,浏览器根据这两个值判断什么样的域名和页面能够读取cookie。第二个方面是第一方cookie和第三方cookie两个概念,第一方cookie是指当前正在查看的网站的cookie,在这个情况下对同源的HTTP请求都读取cookie发送,自然没有任何限制。而第三方cookie来自当前正在查看的网站以外的网站的cookie,第三方cookie可以是会话cookie和持久化cookie,我们正在查看的网站可能包含了第三方的资源,在这种情况下浏览器会因为考虑到同源策略,而判断从当前浏览的网站对站外的请求是否允许读取第三方cookie发送。
cookie的同源策略可能比较晦涩,但是并不难理解,我们拿javascript的同源策略类比,比如AJAX不允许跨域的GET和POST请求,而正常的HTML代码中带有文件请求的标签实际上是属于GET请求,当网站嵌入了第三方的文件资源,也就产生了跨域的请求,同源策略是不可能干预这类正常的请求的,但是从安全的角度仍然有必要限制第三方cookie的存取。
0×03 浏览器的差异和安全缺陷
不同浏览器对于安全的考虑也是不同的,当前的主流浏览器就有很大的区别,Internet Explorer默认设置阻止第三方cookie的读取,而Firefox和Chrome默认是允许所有的cookie。这个是所有浏览器都有的功能,只是默认设置上存在差异,而这些差异才是真正导致CSRF攻击成功与否的关键。
在对第三方cookie的读取上,浏览器实际上普遍存在着一个安全缺陷,那就是浏览网页时不会拦截内存cookie,内存cookie在WEB应用上是套用的session机制,浏览器开发时并没有从Web应用的角度去考虑安全,前面我提到了第三方cookie可以是会话cookie和持久化cookie,而多数浏览器并没有把内存cookie当成一个真正意义上的cookie处理。同时内存cookie有一个特性,这个特性就是内存cookie共享机制,比如从当前浏览器进程新访问的网页或新打开的浏览器窗口都会共享内存cookie,而现在的主流浏览器都流行多标签页浏览,所以给CSRF攻击又带来了便利。
0×04 P3P头的隐患
这一部分我将对Javascript劫持技术做部分的修正,WEB2.0程序员应该熟知JSON技术,简单的想一想,如果一个JSON数据接口是放在二级域名的上,按照cookie的同源策略,跨域请求的第三方cookie是会被拦截的,WEB2.0程序员想使用JSON技术来开发一个大型的WEB应用几乎是不可能实现的,而这个时候P3P头就起了大作用,P3P头是W3C制定的一项关于cookie的标准,现在大型网站的各种WEB2.0应用几乎都使用了P3P头,服务器端只要给HTTP请求返回内容加入如下的HTTP头就能实现跨域访问cookie:
P3P: CP=”CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE GOV”
P3P头解决了Web应用上的难题,却又给Web应用带来了新的安全隐患。浏览器读取了P3P头,就等于打开了第三方cookie的读取的开关,整站的Web应用就被笼罩在CSRF攻击的阴影下,程序员在开发时往往要多考虑一方面的安全因素,那就是站外提交,防止站外提交通常是判断HTTP头Referer,从而分辨请求是来自站内的正常请求,还是黑客在站外构造的CSRF攻击。同时又得考虑HTTP请求没有来源的特殊情况,这类情况可能是网络设备或者浏览器限制了发送HTTP头Referer,一般程序员按常理也会对没有HTTP头Referer的请求放行,这里就存在了一个巨大的风险,程序员没有考虑到FLASH的请求是不会包含HTTP头Referer的,这就是为什么在考虑了CSRF攻击防护的情况下,某些CSRF攻击还能够成功的原因。
0×05 总结和后记
应用和安全是一个矛盾体,Web安全也并不是某些人想象的那样属于奇技淫巧,更深层次的研究会发现很多简单的问题并不简单,由于这篇文档写得比较仓促,不足之处大家可以发EMAIL和我沟通。这是80SEC在2008最后一篇文档,藉此感谢所有支持80SEC的朋友,感谢80SEC团队的其他成员给我的帮助,祝大家2009年更上一层楼。
参考:
http://www.80sec.com/session-hijackin.html
http://blog.csdn.net/lake2/archive/2008/04/02/2245754.aspx
http://www.80sec.com/csrf-with-flash.html
http://www.80sec.com/csrf-securit.html