CSRF
跨站请求伪造
漏洞介绍
跨站点请求伪造(Cross Site Request Forgery)是一种经典的网络攻击方式,它一直是OWASP TOP 10之一,也被称为“One Click Attack”或者Session Riding,通常缩写为CSRF或者XSRF,是一种对网站的恶意利用。尽管听起来和跨站脚本攻击很相似,但它与跨站脚本攻击非常不同,并且攻击方式几乎完全不一样。CSRF与XSS最大的区别就在于,CSRF并没有盗取cookie而是直接利用。跨站脚本攻击利用站点内的信任用户,而CSRF则通过伪装来自受信任用户的请求来利用受信任的网站。与跨站脚本攻击相比,CSRF攻击往往不大流行,因此对其进行防范的措施也相当稀少,另外对于CSRF的防范难度更大,所以被认为比跨站脚本攻击更具危险性。
CSRF危害
你这可以这么理解CSRF攻击:攻击者盗用了你的身份,以你的名义发送恶意请求。CSRF能够做的事情包括:以你名义发送邮件,发消息,盗取你的账号,甚至于购买商品,虚拟货币转账…造成的问题包括:个人隐私泄露以及财产安全。
Session的工作原理
想要深入理解CSRF的攻击特性我们有必要了解一下网站Session的工作原理。
Session大家都不陌生,无论是用.net还是PHP开发过网站的程序员都肯定用过Session对象,然而Session它是如何工作的呢?如果我们把浏览器的Cookie禁用了,大家认为Session还能正常工作吗? 答案是否定的。
在这里举个简单的例子帮助大家理解Session。比如我买了一张高尔夫俱乐部的会员卡,俱乐部给了我一张带有卡号的会员卡。我能享受哪些权利呢?如果我是高级会员卡可以打19洞和后付费喝饮料,而初级会员卡只能在练习场挥杆。我的个人资料都是保存在高尔夫俱乐部的数据库里,我每次去高尔夫俱乐部只需要出示这张高级会员卡,俱乐部就知道我是谁了,并且为我服务了。 因此我们的高级会员卡卡号相当于保存在Cookie的Sessionid;而我的高级会员卡权利和个人信息就相当于服务端的Session对象。
我们知道Http是无状态的协议,它不要求浏览器在每次请求中标明客户端自己的身份,并且浏览器以及服务器之间并没有保持一个持久性的连接用于多个页面之间的访问。为了维持web应用程序状态的问题,每次Http请求都会将本域下的所有Cookie作为Http请求头的一部分发送给服务端,服务器端就可以根据请求中的Cookie所存放的Sessionid去Session对象中找到该会员资料了。
我们理解了Session的工作机制后,CSRF也就很容易理解了。CSRF攻击就相当于攻击用户复制了我的高级会员卡,然后攻击用户就可以拿着这张假冒的高级会员卡去高尔夫俱乐部打19洞,享受美味的饮料,而我这个受害者在月底就会收到高尔夫俱乐部的账单。
CSRF的攻击过程
CSRF攻击过程有以下两个重点:
目标用户已经登录了网站,能够执行网站的功能
目标用户访问了攻击者构造的URL
CSRF攻击举例
受害者Bob 在银行有一笔存款,通过对银行的网站发送请求 “http://bank.example/withdraw?account=bob&amount=1000000&for=bob2”可以使 Bob把1000000块的存款转到Bob2的账号下。通常情况下,该请求发送到网站后,服务器会先验证该请求是否来自一个合法的Session,并且该Session的用户Bob已经成功登陆。黑客Hacker自己在该银行也有账户,他知道上文中的URL可以把钱进行转帐操作。Hacker可以自己发送一个请求给银行:http://bank.example/withdraw?account=bob&amount=1000000&for=Hacker。但是这个请求来自Hacker而非 Bob,他不能通过安全认证,因此该请求不会起作用。
这时,Hacker想到使用CSRF的攻击方式,他先自己做一个网站,在网站中放入如下代码: src=“http://bank.example/withdraw?account=bob&amount=1000000&for=Hacker”,并且通过广告等诱使 Bob 来访问他的网站。当Bob访问该网站时,上述URL就会从Bob的浏览器发向银行,而这个请求会附带Bob浏览器中的 Cookie 一起发向银行服务器。大多数情况下,该请求会失败,因为他要求Bob的认证信息。但是,如果Bob当时恰巧刚访问他的银行后不久,他的浏览器与银行网站之间的Session尚未过期,浏览器的Cookie之中含有Bob的认证信息。这时,悲剧发生了,这个URL请求就会得到响应,钱将从Bob的账号转移到Hacker的账号,而Bob当时毫不知情。等以后Bob发现账户钱少了,即使他去银行查询日志,他也只能发现确实有一个来自于他本人的合法请求转移了资金,没有任何被攻击的痕迹。而Hacker则可以拿到钱后逍遥法外。
CSRF漏洞检测
检测CSRF漏洞是一项比较繁琐的工作,最简单的方法就是抓取一个正常请求的数据包,去掉Referer字段后再重新提交,如果该提交还有效,那么基本上可以确定存在CSRF漏洞。
随着对CSRF漏洞研究的不断深入,不断涌现出一些专门针对CSRF漏洞进行检测的工具,如CSRFTester,CSRF Request Builder等。以CSRFTester工具为例,CSRF漏洞检测工具的测试原理如下:使用CSRFTester进行测试时,首先需要抓取我们在浏览器中访问过的所有链接以及所有的表单等信息,然后通过在CSRFTester中修改相应的表单等信息,重新提交,这相当于一次伪造客户端请求。如果修改后的测试请求成功被网站服务器接受,则说明存在CSRF漏洞,当然此款工具也可以被用来进行CSRF攻击。
CSRF漏洞修复建议
目前防御 CSRF 攻击主要有三种策略:验证 HTTP Referer 字段;在请求地址中添加token并验证;在HTTP头中自定义属性并验证。
验证HTTP Referer字段
根据 HTTP 协议,在HTTP头中有一个字段叫Referer,它记录了该 HTTP 请求的来源地址。在通常情况下,访问一个安全受限页面的请求来自于同一个网站,比如需要访问 http://bank.example/withdraw?account=bob&amount=1000000&for= Hacker,用户必须先登陆bank.example,然后通过点击页面上的按钮来触发转账事件。这时,该转帐请求的Referer值就会是转账按钮所在的页面的URL,通常是以bank.example域名开头的地址。而如果黑客要对银行网站实施 CSRF 攻击,他只能在他自己的网站构造请求,当用户通过黑客的网站发送请求到银行时,该请求的 Referer 是指向黑客自己的网站。因此,要防御CSRF攻击,银行网站只需要对于每一个转账请求验证其Referer值,如果是以bank.example开头的域名,则说明该请求是来自银行网站自己的请求,是合法的。如果Referer是其他网站的话,则有可能是黑客的CSRF攻击,拒绝该请求。
这种方法的显而易见的好处就是简单易行,网站的普通开发人员不需要操心CSRF的漏洞,只需要在最后给所有安全敏感的请求统一增加一个拦截器来检查Referer的值就可以。特别是对于当前现有的系统,不需要改变当前系统的任何已有代码和逻辑,没有风险,非常便捷。
然而,这种方法并非万无一失。Referer的值是由浏览器提供的,虽然 HTTP协议上有明确的要求,但是每个浏览器对于Referer的具体实现可能有差别,并不能保证浏览器自身没有安全漏洞。使用验证 Referer 值的方法,就是把安全性都依赖于第三方(即浏览器)来保障,从理论上来讲,这样并不安全。事实上,对于某些浏览器已经有一些方法可以篡改 Referer值。如果bank.example网站支持 IE6 浏览器,黑客完全可以把用户浏览器的Referer值设为以bank.example域名开头的地址,这样就可以通过验证,从而进行 CSRF 攻击。
即便是使用最新的浏览器,黑客无法篡改Referer值,这种方法仍然有问题。因为Referer值会记录下用户的访问来源,有些用户认为这样会侵犯到他们自己的隐私权,特别是有些组织担心Referer值会把组织内网中的某些信息泄露到外网中。因此,用户自己可以设置浏览器使其在发送请求时不再提供 Referer。当他们正常访问银行网站时,网站会因为请求没有Referer值而认为是CSRF攻击,拒绝合法用户的访问。
在请求地址中添加token并验证
攻击之所以能够成功,是因为黑客可以完全伪造用户的请求,该请求中所有的用户验证信息都是存在于Cookie中,因此黑客可以在不知道这些验证信息的情况下直接利用用户自己的Cookie来通过安全验证。要抵御CSRF,关键在于在请求中放入黑客所不能伪造的信息,并且该信息不存在于Cookie之中。可以在HTTP请求中以参数的形式加入一个随机产生的token,并在服务器端建立一个拦截器来验证这个token,如果请求中没有token或者token内容不正确,则认为可能是CSRF攻击而拒绝该请求。
这种方法要比检查Referer要安全一些,token可以在用户登陆后产生并放于session之中,然后在每次请求时把token从session中拿出,与请求中的token进行比对,但这种方法的难点在于如何把token以参数的形式加入请求。对于 GET 请求,token将附在请求地址之后,这样 URL 就变成 http://url?csrftoken=tokenvalue。 而对于 POST 请求来说,要在 form 的最后加上 ,这样就把 token 以参数的形式加入请求了。
但是,在一个网站中,可以接受请求的地方非常多,要对于每一个请求都加上token 是很麻烦的,并且很容易漏掉,通常使用的方法就是在每次页面加载时,使用JavaScript遍历整个dom树,对于dom中所有的a和form标签后加入token。这样可以解决大部分的请求,但是对于在页面加载之后动态生成的html代码,这种方法就没有作用,还需要程序员在编码时手动添加token。
该方法还有一个缺点是难以保证token本身的安全。特别是在一些论坛之类支持用户自己发表内容的网站,黑客可以在上面发布自己个人网站的地址。由于系统也会在这个地址后面加上token,黑客可以在自己的网站上得到这个 token,并马上就可以发动 CSRF 攻击。为了避免这一点,系统可以在添加 token的时候增加一个判断,如果这个链接是链接到自己本站的,就在后面添加 token,如果是通向外网则不加。不过,即使这个csrftoken不以参数的形式附加在请求之中,黑客的网站也同样可以通过Referer来得到这个token值以发动CSRF攻击。这也是一些用户喜欢手动关闭浏览器Referer功能的原因。
在HTTP头中自定义属性并验证
这种方法也是使用token并进行验证,和上一种方法不同的是,这里并不是把token以参数的形式置于HTTP请求之中,而是把它放到HTTP头中自定义的属性里。通过 XMLHttpRequest这个类,可以一次性给所有该类请求加上 csrftoken这个HTTP头属性,并把token值放入其中。这样解决了上种方法在请求中加入token的不便,同时,通过XMLHttpRequest请求的地址不会被记录到浏览器的地址栏,也不用担心token会透过Referer泄露到其他网站中去。
然而这种方法的局限性非常大。XMLHttpRequest 请求通常用于Ajax方法中对于页面局部的异步刷新,并非所有的请求都适合用这个类来发起,而且通过该类请求得到的页面不能被浏览器所记录下,从而进行前进,后退,刷新,收藏等操作,给用户带来不便。另外,对于没有进行CSRF防护的遗留系统来说,要采用这种方法来进行防护,要把所有请求都改为 XMLHttpRequest 请求,这样几乎是要重写整个网站,这代价无疑是不能接受的。
————————————————
SSRF
服务端请求伪造
SSRF漏洞介绍
SSRF(Sever-Side Request Forgery,服务器端请求伪造)是一种由攻击者构造请求,由服务端发起请求的安全漏洞。一般情况下,SSRF攻击的目标是外网无法访问的内部系统(正因为请求是由服务端发起的,所以服务端能请求到与自身相连而与外网隔离的内部系统)。
SSRF漏洞原理
SSRF形成的原因大都是由于服务端提供了从其他服务器应用获取数据的功能,且没有对目标地址做过滤与限制。例如,黑客操作服务端从指定URL地址获取网页文本内容,加载指定地址的图片等,利用的是服务点的请求伪造。SSRF利用存在缺陷的Web应用作为代理攻击远程和本地的服务器。
首先,我们要对目标网站的架构了解,脑子要有一个架构图。比如 : A网站,是一个所有人都可以访问的外网网站,B网站是一个他们内部的OA网站。
所以,我们普通用户只可以访问a网站,不能访问b网站。但是我们可以同过a网站做中间人,访问b网站,从而达到攻击b网站需求。
正常用户访问网站的流程是:
输入A网站URL --> 发送请求 --> A服务器接受请求(没有过滤),并处理 -->返回用户响应
【那网站有个请求是www.baidu,com/xxx.php?image=URL】
那么产生SSRF漏洞的环节在哪里呢?安全的网站应接收请求后,检测请求的合法性
产生的原因:服务器端的验证并没有对其请求获取图片的参数(image=)做出严格的过滤以及限制,导致A网站可以从其他服务器的获取数据
例如:www.baidu.com/xxx.php?image=www.abc.com/1.jpg
如果我们将www.abc.com/1.jpg换为与该服务器相连的内网服务器地址会产生什么效果呢?
如果存在该内网地址就会返回1xx 2xx 之类的状态码,不存在就会其他的状态码
终极简析: SSRF漏洞就是通过篡改获取资源的请求发送给服务器,但是服务器并没有检测这个请求是否合法的,然后服务器以他的身份来访问其他服务器的资源。
SSRF危害
扫内网
向内部任意主机的任意端口发送精心构造的Payload
DOS攻击(请求大文件,始终保持连接Keep-Alive Always)
攻击内网的web应用,主要是使用GET参数就可以实现的攻击(比如struts2,sqli等)
利用file协议读取本地文件等
SSRF漏洞利用
SSRF漏洞利用测试地址:http://127.0.0.1/web/ssrf.php?url=127.0.0.1/l.php
页面ssrf.php实现的功能是获取GET参数URL,然后将URL的内容返回网页上。如果将请求的网址篡改为http://www.baidu.com,则页面会显示http://www.baidu.com的网页内容,如下所示:
但是,当设置参数URL为内网地址时,则会泄露内网信息,例如,当url=192.168.0.2:3306时,页面返回如下:
说明存在mysql服务。
访问ssrf.php?url=file:///C:/windows/win.ini即可读取本地文件,如下所示:
SSRF漏洞代码分析
在页面SSRF.PHP中,程序获取GET参数URL,通过curl_init()初始化curl组件后,将参数URL带入curl_setopt($ch, CURLOPT_URL, $url),然后调用curl_exec请求该URL.由于服务端会将banner信息返回客户端,所以可以根据banner
SSRF漏洞修复建议
过滤返回信息,验证远程服务器对请求的响应是比较容易的方法。如果web应用是去获取某一种类型的文件。那么在把返回结果展示给用户之前先验证返回的信息是否符合标准。
统一错误信息,避免用户可以根据错误信息来判断远端服务器的端口状态。
限制请求的端口为http常用的端口,比如,80,443,8080,8090。
黑名单内网ip。避免应用被用来获取获取内网数据,攻击内网。
禁用不需要的协议。仅仅允许http和https请求。可以防止类似于file:///、gopher://、ftp:// 等引起的问题。