CSRF漏洞原理及测试方法总结
注:请严格遵守网络安全法,本文章以培养网络安全人才为核心。
跨站请求伪造(也称为 CSRF)是一种 Web 安全漏洞,允许攻击者诱导用户执行他们不打算执行的操作。它允许攻击者部分规避同源策略,该策略旨在防止不同网站相互干扰。GET?POST?
实际上,CSRF不只是只有GET请求可以发起,POST请求也可以发起。
通常情况下,CSRF一般都是采用<iframe>, <img><script>这些带有src
属性的标签发起的,而这些标签只能发起一次GET请求,不能发起一次POST请求,但是对于有些网站来说,这些操作并没用严格区分POST或者GET操作,所以,攻击者可以使用GET来请求表单的提交地址。比如在PHP中,如果使用的是$_REQUEST获取变量,而不是$_POST获取变量,就会发生此问题。(这句化就是说,有些网站对于一些重要的请求操作,应该是只能用POST发起请求的,但是他没有严格限制,使得GET也能发起请求) 对于一个表单来说,用户往往可以通过使用GET来提交表单,比如
我们可以尝试构造一个GET请求:
如果服务器没有对请求方法进行限制,则这个请求会通过。
如果服务器已经区分了POST和GET,对于只能用POST提交的链接,我们也可以构造出一个POST请求。
比如,在一个页面中构造好一个form表单,然后使用Javascript自动提交这个表单。比如,攻击者在www.b.com/test/html下编写如下代码:
攻击者如果将这个页面隐藏在一个不可见的iframe窗口中,则整个自动提交表单的过程,对于用户来说也是不可见的。
CSRF 攻击的影响是什么?
在成功的CSRF 攻击中。攻击者会导致受害者用户无意中执行某项工作。例如,这可能是更改其账户上的电子邮件地址,更改密码或进行资金转账。根据操作的性质,攻击者可能能够完全控制用户的账号。如果受感染的用户在应用程序中具有特权角色,那么攻击者可能能够完全控制应用程序的所有数据和功能。
CSRF 是如何工作的? 要使 CSRF 攻击称为可能,必须具备三个关键条件:
一个相关的动作。 应用程序中存在攻击者有理由诱导的操作。这可能是特权操作(例如修改其他用户的权限)或对用户特定数据的任何动作(例如更改用户自己的密码)。
基于 Cookie 的会话处理。 执行该操作涉及发出一个或多个HTTP请求,并且应用程序仅依赖会话 cookie 来识别发出请求的用户。没有其他机制可用于跟踪会话或验证用户请求。
没有不可预测的请求参数。 执行该操作的请求不包含攻击者无法确定或猜测其值的任何参数。例如,当导致用户更改密码时,如果攻击者需要知道现有密码的值,则该功能不会受到攻击。
例如,假设一个应用程序包含一个允许用户更改其账户上的电子邮件地址的功能。当用户执行此操作时,他们会发出如下 HTTP 请求:
这符合 CSRF 所需的条件:
有了这些条件,攻击者就可以构建一个包含以下HTML的网页:
如果受害者用户访问攻击者的网页,将会发送以下情况:
备注
尽管 CSRF 通常与基于 cookie 的会话处理有关,但它也出现在应用程序自动将一些用户凭据添加到请求的其他上下文中,例如 HTTP 基本身份验证和基于证书的身份验证。
使用Burp Suite 插件 构建 CSRF 攻击
手动创建 CSRF 漏洞利用所需的 HTML 可能很麻烦,特别是在所需的请求包含大量参数或请求中有其他怪癖的情况下。构建 CSRF 漏洞利用的最简单方法是使用内置于Burp Suite Professional的CSRF PoC 生成器:
在 Burp Suite Professional 中的任意位置选择您要测试或利用的请求。
• 从右键单击上下文菜单中,选择参与工具/生成 CSRF PoC。
• Burp Suite 将生成一些 HTML 来触发选定的请求(减去 cookie,它将由受害者的浏览器自动添加)。
• 您可以调整 CSRF PoC 生成器中的各种选项,以微调攻击的各个方面。您可能需要在一些不寻常的情况下执行此操作以处理请求的古怪功能。
• 将生成的 HTML 复制到网页中,在登录到易受攻击网站的浏览器中查看,并测试是否成功发出了预期的请求以及是否发生了所需的操作。
CSRF 与XSS 区别:
CSRF攻击一种需要两个条件:
1.登录受信任的网站,本地生成Cookie; 2.在不注销A情况下,可以访问网站B当然还要另一些方法满足CSRF攻击条件,你无法保证以下情况不会发生: 1.不能保证登录了一个网站,不再打开另一个页面并访问另外的网站。 2.你不能保证你关闭了浏览器后,本地Cookie立刻过期,并且登录的会话未结束。 由此 CSRF 是一种较难防御,又危险极大的漏洞!
如何确认一个web系统存在csrf漏洞
1,对目标网站增删改的地方进行标记,并观察其逻辑,判断请求是否可以被伪造 –比如修改管理员账号时 ,并不需要验证旧密码 ,导致请求容易被伪造 ; –比如对于敏感信息的修改并没有使用安全的token验证,导致请求容易被伪造; 2.确认凭证的有效期(这个问题会提高CSRF被利用的概率) —虽然退出或者关闭了浏览器,但cookie仍然有效,或者session并没有及时过期,导致CSRF攻击变的简单
CSRF是借用户的权限完成攻击,攻击者并没有拿到用户的权限,而XSS是直接盗取了用户的权限,然后实施破坏。
如何确认一个web系统存在CSRF漏洞
1.对目标网站增删改的地方进行标记,并观察其逻辑,判断请求是否可以被伪造
比如修改管理账号时,并不需要验证旧密码,导致请求容易被伪造;
比如对于敏感信息的修改并没有使用安全的token验证,导致请求容易被伪造;
确认凭证的有效期(这个问题会提高CSRF被利用的概率)
CSRF(get/post)实验演示和解析 CSRFget 我们假设我们是Lucy,登陆网站修改信息。
我们点击修改信息并提交,修改成功。我们打开burp查看抓到的数据包
这是我们的请求:GET/vul/csrf/csrfget/csrf_get_edit.phpsex=5&phonenum=54151&add=411&email=www&submit=submit 我们并没有看到CSRF的token,说明并没有防CSRF的措施。 修改get请求,将地址411修改为shanxi
绕过csrf校验: 1.删除CSRF令牌,不校验。 2.通过变换请求,如POST更换GET,但在使用GET方法时跳过验证。(变换请求方法) 3.应用程序在令牌存在时验证令牌,但如果省略令牌则跳过验证。(删除csrf参数) 4.令牌不绑定用户会话(用户加载时获取csrf token,替换用户token) 5.csrf cookie和csrf令牌绑定(替换攻击者的csrf cookie和csrf令牌)
《借刀杀人》 CSRF 构造/发布请求,已经让用户在事先不知道的情况下,让cookie送出cookie的请求,而不是事发先发送给用户的”HTTP 请求”。
CSRF类型
【危害2】漏洞联合——CSRF漏洞使self-XSS漏洞“变废为宝”
存在self-XSS直接漏洞和CSRF漏洞,如果利用self-XSS漏洞则受害者只是自己,如何攻击自己以外的目标?
目标——通过利用CSRF漏洞,使XSSpayload能够攻击自己以外的目标
【危害3】利用CSRF漏洞发出GET请求
漏洞影响
网络场景测试技巧
若能知道浏览器的cookie策略,就会对CSRF的原理与攻击方式会有更深的理解。
浏览器所持有的cookie分成两种,一种是Session Cookie
,叫做临时Cookie
,一种是Third-party Cookie
,叫做本地Cookie,也叫做第三方Cookie。
他们之间的区别在于本地Cookie
是服务器在Set-Cookie时设置了指定的Expire
时间,只有到了制定的Expire
之后,本地Cookie才会失效,所以这种Cookie保存在本地。
而临时Cookie则没用绑定Expire
,所以当浏览器关闭后,临时Cookie也就会失效了,所以这种临时Cookie保存在浏览器中。
在浏览网站的过程中,如果一个网站设置了临时Cookie
, 那么在浏览器的运行过程中,即使浏览器打开了新的网页,临时Cookie
也是有效的。
第三方Cookie
是什么:如果我们访问http://www.a.com
,那么http://www.a.com
就是第一方,如果我们在http://www.a.com
的页面中,在去访问http://www.b.com
,那么http://www.b.com
就是第三方。
如果有这么一种情况,浏览器从一个域的页面中,想要加载另一个域的资源,由于安全原因,一些网络站点会停止本地Cookie
即第三方Cookie的
发送。就是说,我们已经获得了http://www.b.com
的cookie值,当我们在http://www.a.com
页面访问包含在http://www.a.com
页面中的http://www.b.com
的链接时,仍然不会把之前获得的http://www.b.com
的cookie值发送过去
但是这里也是有一个前提的,就是http://a.com
页面包含在http://a.com
页面中的http://www.b.com
的链接时,仍然不会把之前获得的http://www.b.com
的cookie值发过去。
但是这里也是有一个前提的,就是http://www.a.com页面中的http://www.b.com包含在<iframe>, <img>, <script> , <link> 等标签中,因为这些标签在IE中,是禁止浏览器向这些标签中发送第三方cookie的。
当然,并不是所有的浏览器都会禁止,比如火狐浏览器,就默认支持发送第三方cookie。
所以至少对于IE浏览器,攻击者需要精心构造攻击环境,比如可以先诱使用户在当前浏览器中先访问目标站点,使得session cookie有效,然后尝试CSRF。
尽管对于有些CSRF来说,并不是很需要cookie的,但大部分的敏感信息或重要操作都躲藏在认证之后,因此浏览器拦截第三方cookie的发送,一定程度上还是降低了CSRF的威力,可是P3P头的出现,使得一切复杂起来。 P3P Header 是W3C制定的一项关于隐私的标准,全称是The Platform for Privacy Preferences.
如果网站返回给浏览器的HTTP头部中包含有PHP3头,则在某种程度上来说,他会允许浏览器发送第三方cookie,即使是在上文所描述的IE浏览器<iframe>
、<input>
也将不在拦截第三方cookie的发送。
比如存在www.a.com和www.b.com两个域,在www.b上存在一个页面,他是包含www.a.com的一个iframe。
http://www.b.com
的内容为<iframe width=20 height=30 src=http://www.a.com/test.php></iframe>
然后http://www.a.com/test.php
是对a.com域设置cookie的页面,其内容为<?php header("set-cookie:test=axis;path=/")?>
总之这个页面就是为www.a.com设置cookie。当我们在http://www.b.com
这个页面时,点击包含www.a.com的页面,那么就会转到http://www.a.com/test.php
尝试设置cookie,所以浏览器会收到一个cookie。然而等之后,我们在去点击这个点击包含www.a.com的页面,如果上次点击设置cookie成功,那么这次点击就会自动发送刚才收到的cookie,可是由于cookie跨域限制,上次点击没有设置成功cookie,所以这次访问,还是再次接收到和上次一样的cookie,说明上次的cookie并没有发送出去。 但是如果加入了P3P头之后,这种情况就会发生改变,第二次点击那个页面就会发出第一次收到的cookie值。
因为P3P头在网站中的广泛应用,所以在CSRF的防御,不能仅依赖于浏览器对第三方cookie的防御策略,应该从长计议。
常见CSRF防范措施 增加token验证(常用多点做法 ): 1.对关键操作增加token参数,token值必须随机,每次都不一样; 关于安全的会话管理(避免会话被利用): 1.不要在客户端端保存敏感信息(比如身份认证信息); 2.测试直接关闭,退出时,的会话过期机制; 3.设置会话过期机制,比如15分钟内无操作,则自动登录超时; 访问控制安全管理: 1.敏感信息修改时需要对身份进行二次认证,比如修改账号时,需要判断旧密码; 2.敏感信息的修改使用post,而不是get; 3.通过http头部中的referer来限制原页面 增加验证码: 一般用在登录(防暴力破解),也可以用在其他重要信息操作的表单中(需要考虑可用性)
Token产生 1.Token构成
为了防止CSRF攻击,Token要求不能重复,需要含有时间戳信息,签名信息。 下面的图描述了一个token的数据构成: Token的数据结构。
token由三部分组成:
a). 消息[msg]:而msg本身也有两部分组成:一部分:随机字符串,过期时间戳。
b). 分割符[separator]:用于分隔msg部分与加密后生成的signature签名部分,这里用的是”.“
c). 签名[signature]:signature。signature签名,是对“msg消息”用特定算法进行加密后的串。
1.只使用JSON API,使用JavaScript发起AJAX请求是限制跨域的,并不能通过简单的表单来发送JSON,所以,通过只接收JSON可以很大可能避免CSRF攻击。 2.验证HTTP Referer字段,根据 HTTP 协议,在 HTTP 头中有一个字段叫Referer,它记录了该HTTP 请求的来源地址。在通常情况下,访问一个安全受限页面的请求来自于同一个网站,比如上文用户User想要在网站WebA中进行转账操作,那么用户User 3.必须先登录WebA,然后通过点击页面上的按钮触发转账事件。 这时该转账请求的 Referer 值就会是转账按钮所在的页面的URL,而如果黑客要对银行网站实施CSRF攻击,他只能在他自己的网站构造请求,当用户User通过黑客的网站发送请求到WebA时,该请求的Referer 是指向黑客自己的网站。 因此,要防御 CSRF 攻击,网站WebA只需要对于每一个转账请求其Referer值,如果是以网站webA的网址开头的域名,则说明该请求时来自WebA自己多点请求,时合法的,如果 Referer 是其他网址的话,则有可能是黑客的CSRF攻击,拒绝该请求。 4.在请求地址添加token验证 CSRF 攻击之所以能偶成功,是因为黑客可以完全伪造用户的请求,该请求中所有的用户验证信息都是存在于cookie中,因此黑客可以在不知道这些验证信息的情况下直接利用用户自己的cookie来通过安全验证。要抵御CSRF,关键在于请求中放入黑客无所不能伪造的信息,并且该信息存在于cookie之中。可以在HTTP请求中以参数的形式加入一个随机产生的token,并在服务器端建立一个拦截器来验证这个token,如果请求中没有token或者token内容不正确,则认为可能是CSRF攻击而拒绝该请求。
这种方法要比检查Referer 要安全一些,token 可以在用户登录参生并放于 session 之中,然后再每次请求时把token从session中拿出,与请求中的token进行比对。
验证码
验证码是对抗CSRF最简单,最有效的防御方法。 CSRF攻击的过程,往往是在用户不知情的情况下,构造网络请求。而验证码,则强制用户必须与应用进行交互,才能完成最终请求。因此在通常情况下,验证码的存在能很好地遏制CSRF。 但是验证码并不方便,对用户体验并不友好,所以他只能作为一种备选策略存在,无法作为主方法。
Referer Check
Referer Check即参考检查,其实他在互联网中最常见的应用应该是防止图片盗链
,但是他也可以用来检查请求是否存在合法的源
。 常见的互联网应用,页面与页面之间都具有一定的逻辑关系,这就使得每一个正常请求的Referer具有一定的规律。 比如一个‘论坛发帖’的操作,在正常情况下,需要先登录到用户后台,或者访问有发帖功能的页面。在提交发帖的表单时,Referer的值必然是发帖表单所在的页面,但如果Referer的值不是这个页面,甚至不是发帖网站的域,那么极大可能就是CSRF攻击。 但是Referer Check的缺陷也很明显,服务器并不是任何时候都能获取到Referer,很多用户出于隐私的考虑,限制了Referer的发送,而对于浏览器也是同理,某些情况下,比如从HTTPS跳转到HTTP,浏览器也不会发送Referer。 所以,Referer Check其实也不是一个特别好的防御手段,只能作为防御的备用策略。
CSRF的本质
在讲token之前,我们需要知道,CSRF之所以能够攻击成功,除了利用cookie,更重要
攻击者只有预测出URL的所有参数与参数值,才能成功构造一个伪造的请求,反之,则攻击不成功
基于此,有一个解决方案,把参数加密,或者使用一些随机数,让攻击者无法猜测到正确的参数。
比如,一个删除的url是:
http://www.a.com/require?username=123&item=123
但是可以通过参数加密,使得删除的url值为:
http://www.a.com/require?username=1f69f7d19e9455605f6d941de5257ee1&item=123
这样就无法猜测出username的值,从而无法实施攻击
但这种方法存在的缺陷是,加密后的URL非常难读,对用户不友好,其次,如果每次URL值都发生变化,还会使得URL无法被用户收藏。所以这种方法有了一个晋升版,就是构造token。
1、Token值必须是随机的,可以通过使用安全的随机数生成算法实现
2、Token值是私密的,不能被第三方知晓。他可以存放在服务器的cookie中,也可以存放在浏览器的cookie中。但唯独Token值不能直接放在URL中,因为直接放在URL中,可能也会导致浏览器通过Refer得方式泄露。
比如下面这个页面
http://www.a.com/manage?username=abc&token={随机值}
如果在这个页面中包含了一个攻击者能指定地址的图片,比如
<img src="http://www.b.com/a">
那么如果点击这个图片,那么可能就会出现http://www.a.com/manage?username=abc&token={随机值}
作为HTTP请求的Referer发送到http://www.b.com
这个域中,从而导致Token的泄露。
因此在使用Token时,尽量将其放在表单中,把敏感操作由GET改成POST,以表单的形式提交,避免Token泄露
3、Token需要同时放在表单和session中。在提交请求时,服务器只需要验证表单中的Token与用户session(或者cookie)中的Token值是否相同,如果一致,则是合法请求,如果不一致,或者有一个为空,则请求不合法,就可能是CSRF攻击
再服务器端防御CSRF攻击主要有四种策略:
根据HTTP协议,在HTTP头中有一个字段叫Referer,它记录了该HTTP请求的来源地址。在通常情况下,访问一个安全受限页面的请求必须来自于同一个网站。比如某银行的转账是通过用户访问http://bank.test/test?page=10&userID=101&money=10000页面完成,用户必须先登录bank.test,然后通过点击页面上的按钮来触发转账事件。当用户提交请求时,该转账请求的Referer值就会是转账按钮所在页面的URL(本例中,通常是以bank. test域名开头的地址)。而如果攻击者要对银行网站实施CSRF攻击,他只能在自己的网站构造请求,当用户通过攻击者的网站发送请求到银行时,该请求的Referer是指向攻击者的网站。因此,要防御CSRF攻击,银行网站只需要对于每一个转账请求验证其Referer值,如果是以bank. test开头的域名,则说明该请求是来自银行网站自己的请求,是合法的。如果Referer是其他网站的话,就有可能是CSRF攻击,则拒绝该请求。
• 在请求地址中添加token并验证
CSRF攻击之所以能够成功,是因为攻击者可以伪造用户的请求,该请求中所有的用户验证信息都存在于Cookie中,因此攻击者可以在不知道这些验证信息的情况下直接利用用户自己的Cookie来通过安全验证。由此可知,抵御CSRF攻击的关键在于:在请求中放入攻击者所不能伪造的信息,并且该信息不存在于Cookie之中。鉴于此,系统开发者可以在HTTP请求中以参数的形式加入一个随机产生的token,并在服务器端建立一个拦截器来验证这个token,如果请求中没有token或者token内容不正确,则认为可能是CSRF攻击而拒绝该请求。
• 在HTTP头中自定义属性并验证
自定义属性的方法也是使用token并进行验证,和前一种方法不同的是,这里并不是把token以参数的形式置于HTTP请求之中,而是把它放到HTTP头中自定义的属性里。通过XMLHttpRequest这个类,可以一次性给所有该类请求加上csrftoken这个HTTP头属性,并把token值放入其中。这样解决了前一种方法在请求中加入token的不便,同时,通过这个类请求的地址不会被记录到浏览器的地址栏,也不用担心token会通过Referer泄露到其他网站。
针对使用token 防御 CSRF 攻击,我这里做一个简单的介绍:
1.要使Token对攻击者来说难以伪造,我们可以使用伪随机数生成器来构造它 称为Token 随机数,好似在没一个参数中都加入一个随机的Token来此防御,然后把它放到服务器端的session里,并将Token发给用户(注意并没有保存在cookie中);
2.当用户提交请求时,服务器拦截器将POST请求中的Token提取出来,与session中的Token进行比对,相等即执行下一步操作。(这一部分就非常有必要!否则添加了防御的CSRF也是可以绕过的!)
具体代码:
可以看到,同时验证了cookie中的sessionid与POST中的Token。### SDL - 防御与修复方案
<form action
=
"/register"
id
=
'register'
method
=
'POST'
>
<
input
type
=
text name
=
'username'
value
=
''
/
>
<
input
type
=
password name
=
'password'
,value
=
''
/
>
<
input
type
=
submit name
=
'submit'
value
=
'submit'
>
<
/
form>
<form action
=
"/register"
id
=
'register'
method
=
'POST'
>
<
input
type
=
text name
=
'username'
value
=
''
/
>
<
input
type
=
password name
=
'password'
,value
=
''
/
>
<
input
type
=
submit name
=
'submit'
value
=
'submit'
>
<
/
form>
http:
/
/
host
/
register?username
=
test&password
=
passwd
http:
/
/
host
/
register?username
=
test&password
=
passwd
<form action
=
"http://www.a.com/register"
id
=
'register'
method
=
'POST'
>
<
input
type
=
text name
=
'username'
value
=
''
/
>
<
input
type
=
password name
=
'password'
,value
=
''
/
>
<
input
type
=
submit name
=
'submit'
value
=
'submit'
>
<
/
form>
<script>
var f
=
documentElementById(
'register'
);
f.inouts[
0
].value
=
'test'
;
f.inputs[
1
].value
=
'password'
;
f.submit;
<
/
script>
<form action
=
"http://www.a.com/register"
id
=
'register'
method
=
'POST'
>
<
input
type
=
text name
=
'username'
value
=
''
/
>
<
input
type
=
password name
=
'password'
,value
=
''
/
>
<
input
type
=
submit name
=
'submit'
value
=
'submit'
>
<
/
form>
<script>
var f
=
documentElementById(
'register'
);
f.inouts[
0
].value
=
'test'
;
f.inputs[
1
].value
=
'password'
;
f.submit;
<
/
script>
POST
/
email
/
change HTTP
/
1.1
Host: vulnerable
-
website.com
Content
-
Type
: application
/
x
-
www
-
form
-
urlencoded
Content
-
Length:
30
Cookie: session
=
yvthwsztyeQkAPzeQ5gHgTvlyxHfsAfE
email
=
wiener@normal
-
user.com
POST
/
email
/
change HTTP
/
1.1
Host: vulnerable
-
website.com
Content
-
Type
: application
/
x
-
www
-
form
-
urlencoded
Content
-
Length:
30
Cookie: session
=
yvthwsztyeQkAPzeQ5gHgTvlyxHfsAfE
email
=
wiener@normal
-
user.com
<html>
<body>
<form action
=
"https://vulnerable-website.com/email/change"
method
=
"POST"
>
<
input
type
=
"hidden"
name
=
"email"
value
=
"pwned@evil-user.net"
/
>
<
/
form>
<script>
document.forms[
0
].submit();
<
/
script>
<
/
body>
<
/
html>
<html>
<body>
<form action
=
"https://vulnerable-website.com/email/change"
method
=
"POST"
>
<
input
type
=
"hidden"
name
=
"email"
value
=
"pwned@evil-user.net"
/
>
<
/
form>
<script>
document.forms[
0
].submit();
<
/
script>
<
/
body>
<
/
html>
XSS: 存在XSS漏洞 ——> 构造 payload ——> 发送给受害者 ——> 受害者触发 ——> 攻击者得到受害者cookie ——> 攻击者使用受害者权限cookie 登录系统
CSRF: 存在CSRF漏洞 ——> 构造payload ——> 发送给受害者 ——> 受害人点击打开 ——> 受害人执行代码 ——> 受害者完成攻击(不知情)
XSS: 存在XSS漏洞 ——> 构造 payload ——> 发送给受害者 ——> 受害者触发 ——> 攻击者得到受害者cookie ——> 攻击者使用受害者权限cookie 登录系统
CSRF: 存在CSRF漏洞 ——> 构造payload ——> 发送给受害者 ——> 受害人点击打开 ——> 受害人执行代码 ——> 受害者完成攻击(不知情)
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)
最后于 2022-11-3 16:12
被安全小蜘蛛编辑
,原因: 修改错别字