什么是CSRF?
跨站请求伪造(也称为 CSRF)是一种 Web 安全漏洞,允许攻击者诱导用户执行他们不打算执行的操作。它允许攻击者部分规避同源策略,该策略旨在防止不同网站相互干扰。
GET?POST?
实际上,CSRF不只是只有GET请求可以发起,POST请求也可以发起。
通常情况下,CSRF一般都是采用<iframe>, <img><script>这些带有
src
属性的标签发起的,而这些标签只能发起一次GET请求,不能发起一次POST请求,但是对于有些网站来说,这些操作并没用严格区分POST或者GET操作,所以,攻击者可以使用GET来请求表单的提交地址。比如在PHP中,如果使用的是$_REQUEST获取变量,而不是$_POST获取变量,就会发生此问题。(这句化就是说,有些网站对于一些重要的请求操作,应该是只能用POST发起请求的,但是他没有严格限制,使得GET也能发起请求)
对于一个表单来说,用户往往可以通过使用GET来提交表单,比如
1
2
3
4
5
|
<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> |
我们可以尝试构造一个GET请求:
1
|
http: / / host / register?username = test&password = passwd |
如果服务器没有对请求方法进行限制,则这个请求会通过。
如果服务器已经区分了POST和GET,对于只能用POST提交的链接,我们也可以构造出一个POST请求。
比如,在一个页面中构造好一个form表单,然后使用Javascript自动提交这个表单。比如,攻击者在www.b.com/test/html下编写如下代码:
1
2
3
4
5
6
7
8
9
10
11
|
<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> |
攻击者如果将这个页面隐藏在一个不可见的iframe窗口中,则整个自动提交表单的过程,对于用户来说也是不可见的。
CSRF 攻击的影响是什么?
在成功的CSRF 攻击中。攻击者会导致受害者用户无意中执行某项工作。例如,这可能是更改其账户上的电子邮件地址,更改密码或进行资金转账。根据操作的性质,攻击者可能能够完全控制用户的账号。如果受感染的用户在应用程序中具有特权角色,那么攻击者可能能够完全控制应用程序的所有数据和功能。
CSRF 是如何工作的?
要使 CSRF 攻击称为可能,必须具备三个关键条件:
一个相关的动作。应用程序中存在攻击者有理由诱导的操作。这可能是特权操作(例如修改其他用户的权限)或对用户特定数据的任何动作(例如更改用户自己的密码)。
基于 Cookie 的会话处理。执行该操作涉及发出一个或多个HTTP请求,并且应用程序仅依赖会话 cookie 来识别发出请求的用户。没有其他机制可用于跟踪会话或验证用户请求。
没有不可预测的请求参数。执行该操作的请求不包含攻击者无法确定或猜测其值的任何参数。例如,当导致用户更改密码时,如果攻击者需要知道现有密码的值,则该功能不会受到攻击。
例如,假设一个应用程序包含一个允许用户更改其账户上的电子邮件地址的功能。当用户执行此操作时,他们会发出如下 HTTP 请求:
1
2
3
4
5
6
7
|
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 |
这符合 CSRF 所需的条件:
-
攻击者都更改用户账户上的电子邮件地址的操作很感兴趣。执行此操作后,攻击者通常能够触发密码重置并完全控制用户的账户。
-
应用程序使用会话 cookie 来识别发出请求的用户。没有其他令牌或机制来跟踪用户会话。
-
攻击者可以轻松确定执行操作所需的请求参数的值。
有了这些条件,攻击者就可以构建一个包含以下HTML的网页:
1
2
3
4
5
6
7
8
9
10
|
<html> <body> <form action = "https://vulnerable-website.com/email/change" method = "POST" > < / form> <script> document.forms[ 0 ].submit(); < / script> < / body> < / html> |
如果受害者用户访问攻击者的网页,将会发送以下情况:
-
攻击者的页面将触发对易受攻击者的网站的HTTP 请求。
-
如果用户登录到易受攻击的网站,他们的浏览器将自动在请求中包含他们的会话 cookie (假设未使用SameSite cookie)。
-
易受攻击的网站将以正常的方式处理请求,将其为由受害者用户发出,并更改电子邮件地址。
备注
尽管 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 与XSS 区别:
1
2
3
|
XSS: 存在XSS漏洞 ——> 构造 payload ——> 发送给受害者 ——> 受害者触发 ——> 攻击者得到受害者cookie ——> 攻击者使用受害者权限cookie 登录系统 CSRF: 存在CSRF漏洞 ——> 构造payload ——> 发送给受害者 ——> 受害人点击打开 ——> 受害人执行代码 ——> 受害者完成攻击(不知情) |
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被利用的概率)
-
虽然退出或者关闭了浏览器,但cookie仍然有效,或者session并没有及时过期,导致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)
绕过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 的内容:如果能够利用某个单一的RF,攻击者无法获得HTTP请求的 (Cookie 可以但无法查看),也无法得到任何回显(HTTP 响应等)
-
CSRF扩展可以联合其他漏洞(XSS)进行攻击效果:如果使用性
CSRF类型
-
CSRF 按类型分
-
GET - 使用方式使受害者点击构造的 url 发出 GET 请求
http://get.csrfvul.com/payto?name=hacker&moneynumb=100
-
POST - 可以使用方式转换为 GET(可尝试将post请求体改成get形式放至url参数中如果使用正常响应请求GET请求进行csrf攻击)
【危害2】漏洞联合——CSRF漏洞使self-XSS漏洞“变废为宝”
-
场景-
vul.com
存在self-XSS直接漏洞和CSRF漏洞,如果利用self-XSS漏洞则受害者只是自己,如何攻击自己以外的目标?
目标——通过利用CSRF漏洞,使XSSpayload能够攻击自己以外的目标
-
过程
-
构造:攻击者利用CSRF漏洞构造出HTTP请求向
vul.com;
HTTP Request Body中包含了“触发self-XSS漏洞的payload” -
触发:所以当victim(点击链接等)触发CSRF漏洞时,会发出HTTP请求到
vul.comvul.com
,实现受害者在下被XSS攻击
【危害3】利用CSRF漏洞发出GET请求
-
场景
-
目标域
csrfvul.com
存在 CSRF 漏洞 -
攻击者可控域的某个
www.3.comcsrfvul.com
web页面的前端访问代码可向目标域发出请求,如果该受害者则触发页面CSRF -
使用过程
-
http://www.3.com/demo
;1. 攻击者通过中插入代码措施(如JavaScript) -
2.victim访问
http://www.3.com/demo
实现GET-CSRF
漏洞影响
-
CSRF 攻击利用受害者的身份进行操作场景
-
管理员密码 - 使管理员点击构造的链接即可修改其密码。
-
新建单击管理员通知 - 使管理员构造的链接自动添加管理员。
-
漏洞联合(XSS+CSRF)
-
某某通过前台布局者通过提交提交A登录管理后台查看数据管理员xssPayload(漏洞1利用成功但这是某项攻击事件的有效权限后cookie过渡将无法在后台登录)
-
在后台有一个配置“网站名称”的选项存在存储类型xss漏洞(但普通漏洞2仅前台用户会触发管理后台并不会触发)
-
为了 web 后台的权限维度构造 CSRF 请求并利用漏洞 2 使每个普通用户都可以提交漏洞 1 的 xssPayload(也可以设置一定的随时性部分用户也可以提交)
-
管理员日常登录后台查看数据会像他第一次触发漏洞1那样触发。
-
【社交节点蠕虫】 - 如果向好友发送消息的HTTP请求中没有设置CSRF-token请求头可结合XSS则可构造出XSS+CSRF蠕虫影响极大。
-
【拒绝服务】 - 如果通过前台构造xssPayload提交成功打到了管理后台且管理员注销动作无CSRF防御机制可构造payload使管理员一登录则注销。
-
【网络后台权限维度】
网络场景测试技巧
-
请求相同重放 - 智能识别令牌是否正确满足设计:
token动态生成 token会被后端验证且只能被验证一次 经过后端验证后的token立即失效
-
修改令牌值 - 如修改请求正文并发送请求,查看响应正文是否和正常请求的响应正文相同
-
删除令牌值 - 如修改请求正文
para1=aaa&token=
并发送请求,查看响应正文是否和正常请求的响应正文相同 -
完全删除令牌参数 - 如修改请求正文为
para1=aaa
并发送请求,查看响应正文是否和正常请求的响应正文相同 -
HTTP 方法可以由 POST 正确转换为请求
method
,如果可以为 GET 方法
浏览器的Cookie策略
若能知道浏览器的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。
P3P头的副作用
尽管对于有些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的防御
常见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消息”用特定算法进行加密后的串。
CSRF攻击常规防护
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其实也不是一个特别好的防御手段,只能作为防御的备用策略。
使用token
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。
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 漏洞防御策略
再服务器端防御CSRF攻击主要有四种策略:
-
验证HTTP Referer字段
根据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 Example
针对使用token 防御 CSRF 攻击,我这里做一个简单的介绍:
1.要使Token对攻击者来说难以伪造,我们可以使用伪随机数生成器来构造它 称为Token 随机数,好似在没一个参数中都加入一个随机的Token来此防御,然后把它放到服务器端的session里,并将Token发给用户(注意并没有保存在cookie中);
2.当用户提交请求时,服务器拦截器将POST请求中的Token提取出来,与session中的Token进行比对,相等即执行下一步操作。(这一部分就非常有必要!否则添加了防御的CSRF也是可以绕过的!)
具体代码:
1
2
3
4
5
|
# 生成 token session_start(); function set_token(){ $_SESSION[ 'token' ] = md5(time() + rand( 1 , 5000 )); } |
1
2
3
4
5
6
7
8
9
10
11
|
# 使用 token 做验证 function check_token(){ if (isset($_POST[ 'token' ])&&$_POST[ 'token' ] = = = $_SESSION[ 'token' ]) { return ture; } else { return false; } } |
可以看到,同时验证了cookie中的sessionid与POST中的Token。### SDL - 防御与修复方案
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
* web框架 - 启动框架中成熟的CSRF防御功能 * 自定义HTTP请求头(Custom Request Headers) * 如使用`X - CSRF - token:xxxx`标明CSRF_TOKEN的值(即使CSRF利用成功发出了携带Cookie的HTTP请求 但后端判断`X - CSRF - token`不存在则拒绝请求) * One - time Token * 如每次提交表单都包含字段`Token = xxxx`且每次值不同 后端可校验是否正确 * ` Set - Cookie`使用`SameSite`属性 * 后端Response Header` Set - Cookie`中设置`SameSite`属性(由Google引入浏览器 用于缓解CSRF攻击),`SameSite`属性有 3 种值: * `Strict`严格 * 例如 域b.com的Response Header有` Set - Cookie: admin_cookie_strict = xxx; SameSite = Strict`,浏览器中会保存这一Cookie字段`admin_cookie_strict = xxx`,但由于`SameSite = Strict`为 * * 严格 * * ,所以浏览器对(非b.com域下发起的)访问b.com的 * * 任何跨域请求 * * 都不允许携带这一Cookie字段`admin_cookie = xxx`,所以可以防御CSRF攻击。比如从域a.com下构造并发出跨域请求访问b.com(尝试CSRF),绝对不会携带关键的cookie,从而b.com后端鉴权失败,CSRF攻击失败 * `Lax`宽松 - 没有`SameSite`属性的cookie被浏览器默认为`SameSite = Lax` * 例如 域b.com的Response Header有` Set - Cookie: admin_cookie_lax = xxx; SameSite = Lax`,浏览器中会保存这一Cookie字段`admin_cookie_lax = xxx`,但由于`SameSite = Strict`为 * * 宽松 * * ,所以浏览器对(非b.com域下发起的)访问b.com的 * * 多种跨域请求 * * 都不允许携带这一Cookie字段,只有以下 3 种方式(任何一种),才能够携带b.com的cookie`admin_cookie_lax = xxx` * 非同域下的a标签 `<a href = "http://b.com" >< / a>` * 非同域下的GET表单 `<form method = "GET" action = "http://b.com/formdemo" >` * 非同域下的link标签 `<link rel = "prerender" href = "http://b.com" / >` * ` None `无 * `SameSite = None `必须同时指定`Secure`,例如` Set - Cookie: session_none = abc123; SameSite = None ; Secure` * 二次验证 - 安全但影响用户体验(适用于仅对敏感功能处进行防御) * CAPTCHA 增加验证码机制 * 再次输入密码 * 手机验证码 * (不推荐)通过`Referer / Origin`校验来源域名 * 缺陷 1. 只能防御从 "不被信任" 的域发起的伪造的http请求(如果 * * 父、子、兄弟域名 * * 或 * * CORS中被信任的域名 * * 有XSS漏洞 配合构造一个伪造请求 此时referer和Origin的值都是被信任的域 此时“校验来源域名”无法防御) * 缺陷 2. 正常业务如果有 302 跳转 不携带Origin
|
原文始发于微信公众号(信安学习笔记):【Web渗透】CSRF漏洞简介
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论